In JSX, React distinguishes between:
- built-in HTML elements: lowercase names like
div,button,section - custom components: capitalized names like
Card,Button,Profile
A common pattern is to pass the element/component as a prop and render it dynamically.
type BoxProps = { as?: React.ElementType; children: React.ReactNode; }; function Box({ as: Component = 'div', children }: BoxProps) { return <Component>{children}</Component>; } export default function App() { return ( <> <Box as="section">This is a section</Box> <Box as={CustomCard}>This uses a custom component</Box> </> ); } function CustomCard({ children }: { children: React.ReactNode }) { return <div style={{ border: '1px solid #ccc', padding: 12 }}>{children}</div>; } Important rules:
-
as="section"renders a built-in HTML tag. -
as={CustomCard}renders a custom React component. - The component name must start with an uppercase letter.
-
asis just a prop name here; React does not give it special meaning by itself.
A simpler version is also valid:
function Button({ Tag = 'button', children, ...props }) { return <Tag {...props}>{children}</Tag>; } Then:
<Button Tag="a" href="#">Link</Button> <Button Tag={PrimaryButton}>Custom button</Button> 
