Fix: Invalid Slot Name (Reserved) in Astro

Error message:
Invalid slot name.
Components & Hydration 2025-01-25

What Causes This Error?

This error occurs when you use a slot name that is reserved by Astro or conflicts with internal naming conventions. Certain slot names are reserved for Astro’s internal use.

The Problem

---
// Component.astro
---
<!-- ❌ Using reserved slot name -->
<slot name="default" />
---
// Usage
import Component from './Component.astro';
---
<Component>
  <span slot="default">Content</span>
</Component>

The Fix

Use Different Slot Name

---
// Component.astro
---
<!-- ✅ Use non-reserved name -->
<slot name="content" />
<slot name="main" />

Use Unnamed Default Slot

---
// Component.astro
---
<!-- ✅ Unnamed slot is the default -->
<slot />
---
// Usage - content goes to default slot automatically
import Component from './Component.astro';
---
<Component>
  <p>This goes to default slot</p>
</Component>

Common Scenarios

Named Slots Pattern

---
// Card.astro
---
<div class="card">
  <header class="card-header">
    <slot name="header" />
  </header>
  <main class="card-body">
    <slot />  <!-- Default slot -->
  </main>
  <footer class="card-footer">
    <slot name="footer" />
  </footer>
</div>
---
// Usage
import Card from './Card.astro';
---
<Card>
  <h2 slot="header">Card Title</h2>
  <p>Main content goes here (default slot)</p>
  <button slot="footer">Action</button>
</Card>

Multiple Named Slots

---
// Layout.astro
---
<html>
  <head>
    <slot name="head" />
  </head>
  <body>
    <nav>
      <slot name="nav" />
    </nav>
    <main>
      <slot />
    </main>
    <aside>
      <slot name="sidebar" />
    </aside>
  </body>
</html>

Slot Fallback Content

---
// Button.astro
---
<button>
  <slot name="icon">
    <!-- Fallback if no icon provided -->
    <span>→</span>
  </slot>
  <slot>
    <!-- Fallback text -->
    Click me
  </slot>
</button>

Valid Slot Names

<!-- ✅ Good slot names -->
<slot name="header" />
<slot name="footer" />
<slot name="sidebar" />
<slot name="content" />
<slot name="title" />
<slot name="actions" />
<slot name="icon" />
<slot name="before" />
<slot name="after" />

<!-- Use unnamed for default -->
<slot />

Checking for Slot Content

---
// Astro provides Astro.slots to check slot content
const hasHeader = Astro.slots.has('header');
const hasFooter = Astro.slots.has('footer');
---

<div class="card">
  {hasHeader && (
    <header>
      <slot name="header" />
    </header>
  )}

  <main>
    <slot />
  </main>

  {hasFooter && (
    <footer>
      <slot name="footer" />
    </footer>
  )}
</div>

Rendering Slots Programmatically

---
const headerContent = await Astro.slots.render('header');
const hasHeader = headerContent.trim().length > 0;
---

{hasHeader && <header set:html={headerContent} />}

Quick Checklist

  • Don’t use name="default" - use unnamed <slot /> instead
  • Use descriptive slot names: header, footer, sidebar
  • Check Astro.slots.has('name') for conditional rendering
  • Provide fallback content inside <slot> tags
  • Unnamed slot receives all non-slotted children