Components and layouts

Pass component props

Give a component values from its parent and read them through Astro.props.

Props are how a parent passes values into a component. If you know React, Vue, or Svelte, it’s the same concept. Astro components support it too.

At the call site, props look like HTML attributes:

<Hello name="Flavio" />

Inside src/components/Hello.astro, the values arrive on Astro.props. You can read them right in the template:

<p>Hello {Astro.props.name}!</p>

That works. But the common style is to destructure the props into variables in the component script. It keeps the template clean, and it gives you one place to set defaults:

---
const { name, message = 'Hello' } = Astro.props
---

<p>{message} {name}!</p>

message = 'Hello' is the default for a prop the parent might not pass. <Hello name="Flavio" /> renders “Hello Flavio!”. <Hello name="Flavio" message="Welcome" /> renders “Welcome Flavio!”.

Passing anything that isn’t a string

A quoted attribute is always a string. To pass a boolean, a number, an array, or an object, use braces. Braces accept any JavaScript expression:

<Card title="First post" featured={post.isFeatured} />

Inside Card.astro the value keeps its real type. Here we use it to toggle a class:

---
const { title, featured = false } = Astro.props
---

<article class:list={{ featured }}>
  <h2>{title}</h2>
</article>

class:list is an Astro helper. Give it an object, and it adds the class for every key whose value is truthy.

Be careful with the quoting mistake here. featured="true" passes the string "true", not a boolean. The string is truthy, so the class still shows up and you don’t notice. But featured === true is now false, and any comparison like that breaks. When the value isn’t text, use braces.

Props flow one way

The parent owns the data. The child owns the presentation. Values go down, never up.

And remember when this happens. Props are read while Astro renders the component, on the server or in the build. They don’t create reactive state in the browser. Change a value later in client-side code and nothing rerenders.

Defaults and required values

Give every optional prop a default, as with featured = false. For required values, you want to fail loudly during development instead of silently rendering an empty heading.

Try this on your project: create the Hello component, use it once with and once without message, and check both outputs. Then pass featured="true" to Card and compare it with featured={true} in the page source. In the next lesson, TypeScript makes this contract explicit with a typed Props interface, and the wrong string becomes an error you see before you build.

Lesson completed