The Component Model
Components are server-rendered functions
Section titled “Components are server-rendered functions”An Astro component is a .astro file you can import and use in another. It takes props and returns HTML. Because it renders on the server, a component is essentially a function from props to markup — with no client-side lifecycle.
---interface Props { title: string; href: string;}const { title, href } = Astro.props; // props arrive on Astro.props---<a class="card" href={href}> <h3>{title}</h3></a>Using it:
---import Card from '../components/Card.astro';---<Card title="Hello" href="/hello" />Props come in through Astro.props, and you type them by declaring a Props interface in the frontmatter — Astro uses it to type-check usage. There is no useState here; a component runs once to produce HTML.
Slots: composition by passing markup
Section titled “Slots: composition by passing markup”A component often needs to wrap content it doesn’t know in advance. That’s what slots are for — the child markup you put between the component’s tags is rendered where <slot /> appears.
---const { heading } = Astro.props;---<section class="panel"> <h2>{heading}</h2> <slot /> <!-- children go here --></section><Panel heading="Notes"> <p>Any markup here lands in the slot.</p></Panel>For more than one insertion point, use named slots:
<header><slot name="header" /></header><main><slot /></main> <!-- the default slot --><footer><slot name="footer" /></footer><Layout> <h1 slot="header">Title</h1> <p>Body goes in the default slot.</p> <small slot="footer">© 2026</small></Layout>flowchart LR parent["Parent passes markup between the tags"] --> slot["Component renders it at <slot />"] slot --> out["composed HTML"]
Slots are the backbone of layouts: a Layout.astro defines the page shell (head, nav, footer) with a <slot /> for the page body, and every page wraps its content in that layout.
Scoped styles
Section titled “Scoped styles”A <style> tag inside a .astro component is scoped to that component by default — Astro rewrites the selectors so they don’t leak out or clash with other components.
<h1>Title</h1><style> /* This h1 rule applies ONLY to this component's h1, not others on the page. */ h1 { color: rebeccapurple; }</style>You get component-local CSS with plain selectors — no CSS-in-JS, no BEM naming ceremony. When you do want a rule to apply globally, you opt out with <style is:global> (covered in the styles lesson).