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.
  • as is 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>