Skip to main content
The Sidebar component provides a toggleable side panel that can contain navigation, settings, or other content. It supports smooth animations and flexible width configuration.

Structure

The Sidebar component consists of two main subcomponents:
  • Sidebar.Root - The root container that manages sidebar state
  • Sidebar.Content - The visible sidebar panel

Import

import { Sidebar } from '@svelte-atoms/core';

Usage

Basic Sidebar

<script>
  import { Sidebar } from '@svelte-atoms/core';
  let isOpen = $state(false);
</script>

<Sidebar.Root bind:open={isOpen}>
  {#snippet children({ sidebar })}
    <div class="flex size-full">
      <Sidebar.Content class="flex min-w-32 flex-col border-r px-6 py-10" width="300px">
        <button onclick={() => sidebar.state.toggle()}>
          {isOpen ? 'Close' : 'Open'}
        </button>
        <nav>
          <a href="/">Home</a>
          <a href="/about">About</a>
          <a href="/contact">Contact</a>
        </nav>
      </Sidebar.Content>
      
      <main class="flex-1 p-8">
        <h1>Main Content</h1>
        <p>Your page content goes here.</p>
      </main>
    </div>
  {/snippet}
</Sidebar.Root>

Controlled Sidebar

<script>
  import { Sidebar } from '@svelte-atoms/core';
  let sidebarOpen = $state(true);
  
  function toggleSidebar() {
    sidebarOpen = !sidebarOpen;
  }
</script>

<Sidebar.Root bind:open={sidebarOpen}>
  {#snippet children({ sidebar })}
    <div class="flex h-screen">
      <Sidebar.Content width="250px" class="border-r">
        <div class="p-4">
          <h2>Navigation</h2>
          <ul>
            <li><a href="/dashboard">Dashboard</a></li>
            <li><a href="/projects">Projects</a></li>
            <li><a href="/team">Team</a></li>
          </ul>
        </div>
      </Sidebar.Content>
      
      <main class="flex-1">
        <header class="border-b p-4">
          <button onclick={toggleSidebar}>Toggle Sidebar</button>
        </header>
        <div class="p-8">
          <h1>Dashboard</h1>
        </div>
      </main>
    </div>
  {/snippet}
</Sidebar.Root>

Disabled Sidebar

<Sidebar.Root disabled>
  {#snippet children({ sidebar })}
    <div class="flex size-full">
      <Sidebar.Content width="200px">
        <p>This sidebar is disabled and won't toggle.</p>
      </Sidebar.Content>
      <main class="flex-1 p-8">
        <p>Main content</p>
      </main>
    </div>
  {/snippet}
</Sidebar.Root>

Custom Width

<Sidebar.Root>
  {#snippet children({ sidebar })}
    <div class="flex size-full">
      <!-- Wider sidebar -->
      <Sidebar.Content width="400px" class="border-r">
        <div class="p-6">
          <h2>Wide Sidebar</h2>
          <p>More space for content</p>
        </div>
      </Sidebar.Content>
      <main class="flex-1 p-8">
        <p>Main content</p>
      </main>
    </div>
  {/snippet}
</Sidebar.Root>

With Custom Animation

<script>
  import { Sidebar, animateSidebarContent } from '@svelte-atoms/core';
</script>

<Sidebar.Root>
  {#snippet children({ sidebar })}
    <div class="flex size-full">
      <Sidebar.Content 
        width="300px"
        animate={animateSidebarContent({ '0': '0px', '1': 'auto', duration: 300 })}
      >
        <p>Sidebar with custom animation timing</p>
      </Sidebar.Content>
      <main class="flex-1 p-8">
        <p>Main content</p>
      </main>
    </div>
  {/snippet}
</Sidebar.Root>

API Reference

The root container component that manages the sidebar’s state.
open
boolean
default:"false"
Controls whether the sidebar is open or closed. Use bind:open for two-way binding.
disabled
boolean
default:"false"
When true, the sidebar cannot be toggled.
width
string | number
The width of the sidebar when open. Can be a CSS value like '300px' or '20rem'.
factory
Factory<SidebarBond>
Optional factory function to create a custom SidebarBond instance for advanced use cases.
children
Snippet<[{ sidebar: SidebarBond }]>
Render prop that receives the sidebar bond instance for controlling sidebar state.
The visible sidebar panel that slides in and out.
class
string
Additional CSS classes to apply to the sidebar content.
width
string | number
The width of the sidebar. Overrides the width set on Sidebar.Root.
onmount
(this: SidebarBondState) => void
Callback function called when the sidebar content is mounted.
ondestroy
(this: SidebarBondState) => void
Callback function called when the sidebar content is destroyed.
animate
(this: SidebarBondState) => any
Animation configuration for the sidebar. Defaults to animateSidebarContent({ '0': '0px', '1': 'auto' }).
enter
(this: SidebarBondState) => any
Custom enter animation configuration.
exit
(this: SidebarBondState) => any
Custom exit animation configuration.
initial
(this: SidebarBondState) => any
Initial animation state. Defaults to animateSidebarContent({ '0': '0px', '1': 'auto', duration: 0 }).
children
Snippet<[{ sidebar: SidebarBond }]>
The content to display inside the sidebar.
The sidebar bond instance is passed to the children snippet and provides methods to control the sidebar:

Methods

  • sidebar.state.toggle() - Toggles the sidebar open/closed
  • sidebar.state.open() - Opens the sidebar
  • sidebar.state.close() - Closes the sidebar

State

  • sidebar.state.open - Boolean indicating if the sidebar is open
  • sidebar.state.disabled - Boolean indicating if the sidebar is disabled

Styling

The Sidebar component uses the following preset key for styling:
  • sidebar.content - Applied to the sidebar content panel
Default styles include:
  • Background color from theme (bg-card)
  • Border styling (border-border)
You can customize the appearance by:
  1. Using the class prop to add custom classes
  2. Defining custom styles for the sidebar.content preset in your theme
  3. Applying utility classes directly to the component

Animation

The Sidebar component includes built-in animations using the animateSidebarContent function. This function creates smooth width transitions when the sidebar opens and closes.

Custom Animation Example

<script>
  import { Sidebar, animateSidebarContent } from '@svelte-atoms/core';
  
  // Fast animation
  const fastAnimation = animateSidebarContent({ 
    '0': '0px', 
    '1': 'auto', 
    duration: 150 
  });
  
  // Slow animation
  const slowAnimation = animateSidebarContent({ 
    '0': '0px', 
    '1': 'auto', 
    duration: 500 
  });
</script>

Accessibility

  • The sidebar should include proper ARIA attributes for screen readers
  • Toggle buttons should have descriptive labels
  • Keyboard navigation should be supported (Escape key to close)
  • Focus management when opening/closing the sidebar

Accessible Example

<Sidebar.Root bind:open={isOpen}>
  {#snippet children({ sidebar })}
    <div class="flex size-full">
      <Sidebar.Content 
        width="300px" 
        role="navigation" 
        aria-label="Main navigation"
      >
        <button 
          onclick={() => sidebar.state.close()}
          aria-label="Close sidebar"
        >
          Close
        </button>
        <nav>
          <!-- Navigation links -->
        </nav>
      </Sidebar.Content>
      
      <main class="flex-1">
        <button 
          onclick={() => sidebar.state.toggle()}
          aria-label="Toggle sidebar"
          aria-expanded={isOpen}
        >
          Menu
        </button>
      </main>
    </div>
  {/snippet}
</Sidebar.Root>
  • Drawer - Similar slide-out panel with overlay
  • Dialog - Modal dialog component
  • Accordion - Collapsible content sections
  • Menu - Navigation menus

Build docs developers (and LLMs) love