Slots and Composition

By Syncfusion®, Inc. · Last updated

The default slot, named slots, fallback content, passing slots to child components, Astro.slots, the class:list, set:html, set:text and is:raw directives, Astro 7's HTML rules, and composing components.

Slots

  • Props pass values into a component.
  • Sometimes you want to pass HTML instead: a paragraph, a list, even other components.
  • A slot is a hole in a component where the HTML you put inside the tag appears.
  • In this lesson, you will build wrapper components with slots and learn Astro's template directives.

Simple lesson: props carry values, slots carry HTML.

A Real-World Example

  • Asha wants a coloured "Note" box in many posts.
  • Sometimes the box holds one sentence. Sometimes a list. Sometimes a code sample.
  • She cannot know the content ahead of time, so a prop is the wrong tool.
  • She writes one Note component with a <slot />. Whatever she puts between <Note> and </Note> appears inside the box.

Press ▶ Run. The same Note box wraps two different contents.

What happened:

  • <slot /> in Note.astro marks where the content goes.
  • The first Note got a paragraph. The second got a list.
  • The box's HTML and style are written once.

What You Will Learn

In this lesson, you will learn:

  1. How the default <slot /> works.
  2. How named slots fill several places in one component.
  3. How to show fallback content when a slot is empty.
  4. How to check slots with Astro.slots.
  5. How to pass slots on to a child component.
  6. The directives class:list, set:html, set:text and is:raw.
  7. The HTML rules that Astro 7 checks.

The Default Slot

  • Default slot = <slot /> with no name.
  • Everything between a component's opening and closing tags goes there.
  • Content with no slot="..." attribute goes to the default slot.

Animation: a paragraph written between Note tags moves into the slot hole of the Note component.

The page

<Note> </Note>

<p>Astro is fast</p>

Note.astro <aside>

<slot /> is here The content between the tags fills the slot.

Whatever you write between the tags lands where the slot is.

Simple lesson: put <slot /> where the outside content should appear.

Named Slots and Fallback Content

Named Slots

  • Named slot = <slot name="footer" />. A component can have many.
  • To fill it, add slot="footer" to an element: <p slot="footer">Thanks!</p>.
  • Everything without a slot attribute still goes to the default slot.

Fallback Content

  • Fallback content = what a slot shows when nobody fills it.
  • Write it between the slot tags: <slot name="footer">No footer yet.</slot>.

Press ▶ Run. The first card fills both slots. The second leaves the footer empty, so it shows the fallback.

  • The order of the children does not matter. Each one goes to the slot it names.
  • <Fragment slot="footer"> fills a slot with several elements and no extra wrapper.

Simple lesson: name on the slot, slot on the content. Fallback goes between the slot tags.

Checking and Passing Slots

Astro.slots

  • Astro.slots.has("footer") is true when the parent filled the footer slot.
  • Use it to skip a wrapper that would be empty.
  • await Astro.slots.render("footer") gives you the slot's HTML as a string. You rarely need it.

Passing Slots to Child Components

  • A component can pass a slot it received on to a component inside it.
  • Write <slot name="footer" slot="footer" /> inside the child's tags.
  • Read it as: "take my footer slot and put it into the child's footer slot".
  • Open HTML sent to browser. Only the first post has a <footer> tag.
  • PostBox wraps Card, and passes its own footer slot down to it.

Simple lesson: Astro.slots.has() checks a slot. <slot name="x" slot="x" /> passes it on.

Template Directives

  • Directive = a special attribute with a colon, such as class:list. Astro reads it at build time.

class:list

  • class:list builds the class attribute from a list.
  • Strings are always added. An object adds each key whose value is true.
  • Example: class:list={["card", { featured: isTop, draft: !isPublished }]}.

set:html

  • set:html puts a string inside an element as HTML.
  • Use it for HTML you made or trust, such as a rendered blog post.

set:text

  • set:text puts a string inside an element as plain text.
  • Any < or > in it is shown as characters, never run as HTML.

is:raw

  • is:raw tells Astro not to read { } inside an element.
  • Useful when you want to show Astro code as an example.

What to compare in HTML sent to browser:

  • class: it became class="card featured draft".
  • set:html: <em> is a real tag. The word "Written" is in italics.
  • set:text: <b> is shown as text, so the visitor sees the tags.
  • is:raw: {name} stayed as text.

Never pass text typed by a visitor to set:html. If they type a <script>, it runs in every reader's browser. This attack is called cross-site scripting (XSS). Normal { } expressions and set:text are safe: they show the text without running it.

Simple lesson: class:list for classes, set:html only for trusted HTML, set:text for anything else.

HTML Rules in Astro 7

Astro 7 has a new compiler. It is stricter than earlier versions.

Unclosed Tags Are Now Errors

  • Every tag you open must be closed: <p>...</p>, <div>...</div>.
  • Browsers forgive a missing </p>. The Astro 7 compiler does not. It stops the build.
  • Void elements = tags that never have content, so they need no closing tag: <img>, <br>, <hr>, <input>, <meta>, <link>.

Valid Tag Nesting

  • Some tags cannot hold others. A <p> cannot hold a <div>.
  • Astro 7 keeps your tags as you wrote them. The browser may then move them, and your styles may break.
  • Write HTML the browser allows: put a <div> beside a <p>, not inside it.

Self-Closing Tags

  • Any tag may be written as self-closing: <div /> becomes <div></div>.
  • Components with no content are usually written that way: <Footer />.

Press ▶ Run. The build stops. Read the terminal, then close the paragraph and run again.

  • The terminal names the tag and the line.
  • <img> and <br> are fine without a closing tag.

In this lab, the browser runs Astro's earlier compiler, which closes tags silently. So the lab adds the same "never closed" check that Astro 7 makes. The message on your computer looks different, but the rule is the same.

Simple lesson: close every tag except void tags. Astro 7 will not guess for you.

Reusing Components

Composing with Slots

  • Slots let you build "frame" components: cards, boxes, sections, tabs.
  • The frame decides the look. The page decides the content.
  • You will use the same idea for whole pages in Layouts and the Document Head.

Props or Slots?

Use a prop when:

  • the value is short text or a number, such as a title or a count,
  • the component must change its look from it, such as tag="Astro".

Use a slot when:

  • the content is HTML, such as paragraphs, lists or other components,
  • the content changes a lot from place to place.

Start with props. Switch to a slot when you notice you are passing HTML as a text prop.

Simple lesson: values as props, HTML as slots. Many components use both.

TL;DR

  1. Slot = <slot />, a hole for the HTML between a component's tags.
  2. Named slot = <slot name="x" />, filled by slot="x" on an element.
  3. Fallback = content between the slot tags. Shown when the slot is empty.
  4. Astro.slots.has("x") = was slot x filled?
  5. Pass a slot on = <slot name="x" slot="x" />.
  6. class:list = classes from strings and true/false objects.
  7. set:html = trusted HTML only. set:text = always plain text.
  8. is:raw = leave { } as text.
  9. Astro 7 rule = close every tag, except void tags like <img> and <br>.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
No <slot /> in the componentChildren show up by themselvesAdd <slot /> where they should goThe content between the tags disappears
slot="footer" with no matching slotAny name worksUse the same name as <slot name="footer" />The content is dropped
Visitor text in set:htmlIt is just textUse { } or set:textXSS: a script runs in readers' browsers
Missing </p> or </div>The browser fixes itClose every tagAstro 7 stops the build
<div> inside <p>Any tag can hold any tagPut block tags beside the paragraphThe browser moves tags and styles break
An empty wrapper for a missing slotEmpty tags are harmlessCheck with Astro.slots.has()Empty boxes with borders appear

Check Yourself

Exercises

What to Remember

  • <slot /> is where a component's children go.
  • Named slots fill several places. Fallback content fills an empty slot.
  • Astro.slots.has() checks a slot. <slot name="x" slot="x" /> passes it on.
  • class:list builds classes. Use set:html only for trusted HTML.
  • Close every tag in Astro 7, except void tags.

Next: Layouts and the Document Head, where one component frames every page of the site.