Astro has
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.
Element
prop as a local variable.<slot />
.---
const { Element, ...props } = Astro.props;
---
<Element {...props}><slot /></Element>
Uppercase prop names can look out of place in templates. Destructure and rename the Element
prop in one to provide a more ergonomic/conventional authoring experience.
---
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.
class:list
Astro has a class:list
directive for orchestrating dynamic classes. Provide the class:list
directive an array with both provided and component classes.
class:list
is smart and automatically removes duplicate classes.
---
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>
Note: class
needs to be renamed when destructured because values can not be assigned to reserved words.
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>
Astro provides
If you're using dynamic tags for static layouts — like me — this isn't an issue.
Astro supports the "polymorphic as prop" pattern popular in React. And the additional standard tooling of TypeScript and class:list
directive make it even easier to consistently implement.
Also published here.