Recommended Free Tools
Use an as prop when a component should choose its rendered element from a prop, and use asChild when a caller should provide the element that receives a primitive’s props and behavior. Neither is a built-in React API: as is a component-design pattern, while asChild is documented by Radix as a composition pattern based on cloning and merging props. The right choice depends on who owns the target and whether that target preserves the behavior and accessibility your component requires.
What do `as` and `asChild` mean?
Both patterns let a reusable component render something other than its default element, but they put the choice in different hands.
As an Amazon Associate I earn from qualifying purchases.
as: The wrapper chooses the target through a prop, such as<Button as="a" href="/docs">. The component implementation renders that target and passes it props.asChild: The caller supplies the child element, and the primitive composes onto it. In Radix, a component such as a Tooltip trigger can omit its default element, clone its child, and merge the props and behavior it needs onto that child.
Radix documents asChild for primitive parts that render DOM elements. Its Tooltip trigger, for example, defaults to a button but can compose onto an anchor. See the Radix composition guide and Radix Slot documentation for the library’s behavior and API.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallHow do I type a polymorphic React component with an `as` prop?
Type the target and its props together. A common design is to make the target a generic parameter, derive the props accepted by that target, remove any keys that the wrapper defines itself, then add the wrapper’s own props. This is a practical pattern rather than an official React or TypeScript standard utility; the React and Radix documentation do not prescribe a single canonical polymorphic type.
#1 Best Overall
Example: a button-like component targeting an anchor
This React 19-oriented sketch shows the type relationship. It supports intrinsic elements such as button and a; a library that also supports arbitrary custom components should add and test an appropriate component-target type.
import type { ComponentPropsWithRef, ElementType, ReactNode } from "react";
type ButtonOwnProps = {
tone?: "primary" | "quiet";
children: ReactNode;
};
type PolymorphicProps<T extends ElementType> =
ButtonOwnProps &
{ as?: T } &
Omit<ComponentPropsWithRef<T>, keyof ButtonOwnProps | "as">;
function Button<T extends ElementType = "button">(
{ as, tone = "primary", ...props }: PolymorphicProps<T>
) {
const Tag = as ?? "button";
return <Tag data-tone={tone} {...props} />;
}
<Button type="button">Save</Button>;
<Button as="a" href="/docs">Read the docs</Button>;
The generic target lets TypeScript infer the target-specific props: an anchor target can accept href, while a button target can accept button attributes. The Omit prevents collisions between target props and wrapper-owned props from producing an ambiguous public API.
Decide prop ownership and collisions
When the wrapper and target both define a prop name, decide which meaning wins and encode it in the type and implementation. In the sketch, wrapper-owned keys are omitted from the target-derived props, and the wrapper controls tone. Be explicit about this rule in public component documentation. The spread order also matters: props applied after the spread can override caller values, while props before it can be overridden by the caller.
Rank #2
- TypeScript implements a superset of syntax for strictly typed development, facilitating deep static analysis and enhanced development environment integration. The compiler translates source into standard script formats, ensuring parity across any runtime.
- TypeScript is ideal for front-end developers, full-stack engineers, and software architects who build large-scale web applications. It serves those looking to improve code excellence, reduce bugs through static checking, and maintain complex projects more.
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Keep supported targets meaningful
A type that accepts every possible component is not automatically a sound component API. Limit targets to those that can honor the wrapper’s contract. A control that promises button behavior should not silently become a non-interactive element just because its type permits it. For broad library APIs, test inference for the default target, alternate intrinsic targets, custom components, and ref types against the exact React and @types/react versions you support.
How does Radix `asChild` composition work?
With Radix asChild, the primitive uses its child in place of its default DOM element and merges its required props and behavior onto that child. For a wrapper component, the documented basic pattern is to render Slot.Root when asChild is true and the normal element otherwise. If the wrapper has multiple children, Radix documents Slottable to mark which child should receive the merged props. Check the Slot documentation for details and confirm its API against the version installed in your project; the cited Slot page identifies version 1.3.0.
The supplied child must work as the target, not just look like one. A custom child component needs to accept and pass through the props supplied by the primitive, as well as the ref when the primitive needs one. If it drops those props, the primitive’s event handlers, accessibility attributes, or other behavior may not reach the rendered DOM node.
Forward props and refs from custom children
For React 18 and earlier, Radix’s composition guide demonstrates React.forwardRef for leaf components that may be used under asChild. The component should spread received props onto the intended DOM element and attach the ref there.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsimport * as React from "react";
type LinkProps = React.ComponentPropsWithoutRef<"a">;
const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
(props, ref) => <a {...props} ref={ref} />
);
Link.displayName = "Link";
This example targets the earlier ref pattern. React 19 changes how function components receive refs, so do not copy a ref type and implementation across React majors without checking the versions your package supports.
How do refs work in React 19?
In React 19, a function component can read ref as a prop, and new function components no longer need forwardRef. React’s current reference marks forwardRef deprecated in React 19 in favor of passing ref as a prop. For earlier React versions, forwardRef remains the documented compatible approach. See the React 19 upgrade guide and React forwardRef reference.
React treats key and, historically, ref specially rather than as ordinary props. React 19’s function-component ref support changes that ref guidance, but does not make key a normal prop. The upgrade guide also covers TypeScript changes, including use of the scoped React.JSX namespace rather than relying on a global JSX namespace. Keep component declarations, runtime code, and installed React types aligned with the React major you target.
Which should I use for a Button: `as` or `asChild`?
Choose based on who should control the rendered element and how the component’s behavior reaches it.
| Design question | as |
asChild |
|---|---|---|
| Who chooses the target? | The wrapper caller selects it through the as prop. |
The caller supplies a child; the primitive composes onto that child. |
| How do props reach it? | The wrapper renders the target and passes props through its implementation. | Radix Slot clones the immediate child and merges props onto it. |
| What is the central type concern? | Connect the selected target to its target-derived props, while resolving wrapper-owned name collisions. | The child must accept injected props and any needed ref; the wrapper can check for a child element but cannot guarantee every custom child forwards correctly. |
| What needs careful review? | Whether each supported target matches the component’s promised semantics and behavior. | Whether the supplied child forwards props and refs and preserves the primitive’s required interaction behavior. |
Use as when the wrapper should own the target choice and offer a target-aware API. Use asChild when callers already have the element or component they want to render and the primitive should add its behavior to it. Neither pattern is universally better; Radix documents its own composition API, not a rule for every design system.
Best Value
What accessibility and behavior must the target preserve?
The rendered target must support the interaction the component claims to provide. Radix warns that changing a focusable trigger into a div can make it inaccessible. Its composition guide puts responsibility on the author changing the underlying element to keep it accessible and functional.
For a trigger, check that the resulting element is focusable and responds to the pointer and keyboard events the primitive requires. For a control presented as a button, prefer a real button unless the API intentionally supports another semantic element and implements the expected behavior. For an anchor, provide a meaningful destination when navigation is intended. TypeScript can help express prop compatibility, but it cannot establish that a target’s runtime semantics are correct.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.




