Styled-Components `as` Prop: Reusing Styles Across Tags Without Losing Control
The `as` prop lets a styled component render as a different HTML tag while keeping its styles. Here is how it works, where it breaks, and how to verify the result.
27 Sept 2026, 15:39 UTC

You have a styled.button that looks perfect. Tomorrow the design team asks for a promotional banner with the same padding, border radius, and hover shadow—but it must be a link, not a button. Copying the style block into a new styled.a works, yet it leaves you maintaining two definitions that must stay in sync forever.
The as prop in styled-components solves this by letting a single styled component render as a different HTML tag or React component while keeping the generated CSS class unchanged. The catch is that swapping the tag changes browser semantics, external CSS matching, and ref behavior. Here is how it works, a worked example, and the trade-offs to verify before shipping.
What the as Prop Actually Changes
In styled-components v5 and v6, the library generates a unique class name, injects the associated CSS, and renders an element with that class. When you pass as, the library swaps the rendered element but leaves the class name and injected CSS untouched.
Visually, the contract stays identical. A styled.button rendered with as="a" produces an <a> carrying the same class, so the browser applies the same rules. What changes is everything CSS does not control: focus behavior, keyboard interaction, default accessibility roles, and how external stylesheets match the element.
Worked Example: HTML Tags and Custom Components
In your component file, start with a base button style:
import styled from 'styled-components';
const Button = styled.button`
display: inline-flex;
padding: 0.5rem 1rem;
background: #2563eb;
color: white;
border-radius: 0.25rem;
text-decoration: none;
&:hover {
background: #1d4ed8;
}
`;
Rendering it as an anchor is a one-line change:
<Button as="a" href="/pricing">View pricing</Button>
The as prop also accepts React components. This is useful when you need framework-specific behavior, such as a router link, with the same visual style. The target component must forward refs and spread the props it receives; otherwise styled-components cannot pass the generated class or attach a ref correctly.
import { forwardRef } from 'react';
const RouterLink = forwardRef(({ to, children, ...rest }, ref) => (
<a ref={ref} href={to} {...rest}>
{children}
</a>
));
<Button as={RouterLink} to="/pricing">Router pricing</Button>
In the snippet above, RouterLink forwards its ref to the underlying <a> and spreads ...rest so the generated class reaches the DOM node. Omitting either step can cause styles or ref attachment to fail silently.
Where as Creates Hidden Costs
Element-Specific CSS Selectors
Styles inside the styled template are scoped to the generated class, so they travel with the component. Styles defined outside styled-components do not. A global rule like button:hover { box-shadow: ... } will not match an <a> rendered via as. The same applies to descendant selectors such as .card button. Audit external CSS before swapping tags.
Accessibility and Native Behavior
A native <button> is focusable, triggers on Enter and Space, and exposes an implicit button role. An <a> with an href is focusable and triggers on Enter, but not Space. If the component runs JavaScript on click rather than navigating, you may need role="button" and a keydown handler. Rendering a styled button as a <div> removes focusability and semantic meaning unless you add ARIA (Accessible Rich Internet Applications) attributes and tabindex.
Ref Forwarding with Custom Components
When as points to a custom component, styled-components passes a ref expecting it to reach a DOM node. If the component does not use forwardRef, the ref may resolve to null or to the component instance instead of the element. This breaks focus management, scroll-into-view logic, and libraries that expect a DOM node.
Tag-Specific CSS Properties
Some CSS properties only affect certain elements. display: table-row has no effect on a <div>. If your styles rely on layout properties tied to the original tag, swapping to an incompatible element can cause silent layout regressions.
Practical Verification
Because as changes the DOM without changing the class name, the most direct check is to inspect the rendered markup. In your browser's developer tools, confirm the tag name matches your as value and the class attribute still contains the styled-components generated class.
For automated coverage, render each as variant in a test harness and snapshot the output. A snapshot catches accidental changes to the rendered tag or class list. If you use server-side rendering, wrap the tree in ServerStyleSheet—the styled-components utility that collects injected styles during render—and verify the collected styles include your component's rules; the as prop does not alter which CSS is injected, but confirming the sheet contents protects against unrelated regressions.
When to Reach for Something Else
The as prop is a scalpel, not a foundation. It works best for one-off semantic swaps where the visual contract is identical and interactive behavior is compatible. If you pass as in many places, or consumers routinely need different tags, you likely have a polymorphic component rather than a styled button. Extract shared styles into a base component or use a TypeScript polymorphic pattern so the rendered element is explicit.
Treat every as swap as a small semantic decision. Verify the tag, check external CSS, and confirm the accessibility contract. When those line up, as removes duplication without adding risk.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.