TypeScript
Most components in @atom-learning/components are polymorphic: they render a sensible default element which you can change with the as prop. The accepted props and the ref type follow the element you pass — as="a" unlocks href and types the ref as HTMLAnchorElement.
<Box as="a" href="/about">About</Box>
// href is not valid on the default div — type error
<Box href="/about">About</Box>
Extracting prop types
React.ComponentProps works on any component in the library and returns the props for its default element, including any variant props with their exact unions.
import * as React from 'react'
import { Button } from '@atom-learning/components'
type ButtonSize = React.ComponentProps<typeof Button>['size']
// 'sm' | 'md' | 'lg' | 'xl' | ...
Extracting props for a different element
Props extracted with React.ComponentProps describe the default element only, so they exclude element-specific props such as href, and the extracted as key is intentionally unusable. To extract the props a component accepts when rendered as a different element, use StyledComponentProps and pass the element as the second argument.
import type { StyledComponentProps } from '@atom-learning/components'
// Box rendered as an anchor: includes href, ref is HTMLAnchorElement
type AnchorBoxProps = StyledComponentProps<typeof Box, 'a'>
Building your own polymorphic wrapper
A wrapper component that forwards as needs to declare it explicitly — the extracted props can't carry a polymorphic as, because the moment as changes, the native props and ref type change with it. Replace the key rather than intersecting it:
type CardProps = Omit<StyledComponentProps<typeof Box>, 'as'> & {
as?: React.ElementType
}
const Card = ({ as, ...rest }: CardProps) => <Box as={as} {...rest} />
Note that a plain intersection (StyledComponentProps<typeof Box> & { as?: React.ElementType }) does not work — the two as declarations intersect to never. Always Omit the original key first, or narrow it to the elements your wrapper actually supports, for example as?: 'label' | 'legend'.