Astro has — a way to take an element or component as a prop. dynamic tags I had trouble finding the feature because the React community calls this pattern the "polymorphic as prop". Because we enjoy our pseudo-computer-science bullshit artisinally. Dynamic tags are simple to implement in Astro. No-fuss implementation Take a prop as a local variable. capitalized Element Render that prop as a template tag. Take and spread rest-props. Render children using Astro's un-named . <slot /> --- const { Element, ...props } = Astro.props; --- <Element {...props}><slot /></Element> Destructure and rename the element prop (for convenience or convention) Uppercase prop names can look out of place in templates. Destructure and rename the prop in one to provide a more ergonomic/conventional authoring experience. Element --- const { as: Element, ...props } = Astro.props; --- <Element {...props}><slot /></Element> Astro templates require that dynamic tags be capitalized. Renaming the element prop is a convent way to follow that requirement while providing a more conventional API to consumers. Accept and de-duplicate classes with class:list Astro has a directive for orchestrating dynamic classes. Provide the directive an array with both and classes. class:list class:list provided component is smart and automatically removes duplicate classes. class:list --- const { as: Element = "div", class: providedProps, ...props } = Astro.props; const componentClasses = "prose prose-slate dark:prose-invert"; --- <Element {...props} class:list={[componentClasses, providedProps]}> <slot /> </Element> needs to be renamed when destructured because values can not be assigned to reserved words. Note: class Complete with TypeScript interface This is my completed component, with the TypeScript interface. Yours needs will likely vary. --- interface Props { as?: "body" | "main" | "article"; class?: "string"; } const { as: Element = "div", class: providedProps, ...props } = Astro.props; --- <Element {...props} class:list={[componentClasses, providedProps]}> <slot /> </Element> BEWARE: dynamic tags don't honor hydration client directives Astro provides for hydrating client-side UI. Those don't work with dynamic tags. client directives If you're using dynamic tags for static layouts — like me — this isn't an issue. Takeaways Astro supports the "polymorphic as prop" pattern popular in React. And the additional standard tooling of TypeScript and directive make it even easier to consistently implement. class:list Also published . here