# Sidebar

> A collapsible, grouped navigation rail with labelled sections, a current-item accent, and badges folded into each item's accessible name.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Navigation
- Tags: sidebar, nav, rail, collapsible, compound, badge
- Docs: https://fancy-ui.rama.app/docs/components/sidebar
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/sidebar

## Import

```svelte
<script lang="ts">
  import { Sidebar } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { Sidebar } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `"Sidebar"` | Accessible name for the nav landmark. |
| `collapsed` | `boolean` | `false` | Whether the sidebar is collapsed to an icon-only rail. Plain, not bindable — nothing inside the compound ever changes it itself. |
| `class` | `string` | — | Additional CSS classes, merged onto the root. |
| `ref` | `HTMLElement \| null` | `null` | Bindable reference to the root nav element. |
| `SidebarGroup.label` (required) | `string` | — | The section heading, e.g. "General". |
| `SidebarGroup.class` | `string` | — | Additional CSS classes, merged onto the group. |
| `SidebarItem.href` | `string` | — | Renders an <a> when set; a <button type="button"> otherwise. |
| `SidebarItem.current` | `boolean` | `false` | Marks this as the current item — aria-current="page" plus the accent left bar. |
| `SidebarItem.badge` | `string \| number` | — | A count or short flag, e.g. 4, rendered as a pill. |
| `SidebarItem.badgeLabel` | `string` | — | What the badge means, folded into the accessible name. Defaults to just the badge value. |
| `SidebarItem.disabled` | `boolean` | `false` | Disables both the click and keyboard-activation paths. |
| `SidebarItem.onclick` | `(event: MouseEvent) => void` | — | Native click handler, for the button branch. Never called while disabled. |
| `SidebarItem.class` | `string` | — | Additional CSS classes, merged onto the item. |
| `SidebarItem.ref` | `HTMLAnchorElement \| HTMLButtonElement \| null` | `null` | Bindable reference to the item's interactive element. |
| `SidebarItem.sound` | `boolean` | `false` | Plays select when a sidebar item that is not already current is activated, once the user has enabled sound |
| `SidebarSeparator.class` | `string` | — | Additional CSS classes, merged onto the hairline. |
| `SidebarSeparator.ref` | `HTMLHRElement \| null` | `null` | Bindable reference to the <hr> element. |
| `SidebarFooter.class` | `string` | — | Additional CSS classes, merged onto the footer row. |
| `SidebarFooter.ref` | `HTMLDivElement \| null` | `null` | Bindable reference to the footer's root element. |

## Snippets

| Snippet | Description |
| --- | --- |
| `children` | SidebarGroup, SidebarSeparator and SidebarFooter. |
| `SidebarGroup.children` | The SidebarItems in this section. |
| `SidebarItem.icon` | A decorative glyph or icon, shown even while the sidebar is collapsed. |
| `SidebarItem.children` | The item's label. Moves to sr-only text while collapsed — never removed. |
| `SidebarFooter.avatar` | A decorative avatar, shown even while the sidebar is collapsed. |
| `SidebarFooter.children` | The name / text next to the avatar. sr-only while collapsed. |

## Examples

### Basic Usage

```svelte
<script lang="ts">
	import { Sidebar, SidebarGroup, SidebarItem } from "fancy-ui-svelte";

	let current = $state("dashboard");
</script>

<Sidebar>
	<SidebarGroup label="General">
		<SidebarItem
			sound
			href="#dashboard"
			current={current === "dashboard"}
			onclick={() => (current = "dashboard")}
		>
			Dashboard
		</SidebarItem>
		<SidebarItem
			sound
			href="#projects"
			current={current === "projects"}
			onclick={() => (current = "projects")}
		>
			Projects
		</SidebarItem>
		<SidebarItem
			sound
			href="#settings"
			current={current === "settings"}
			onclick={() => (current = "settings")}
		>
			Settings
		</SidebarItem>
	</SidebarGroup>
</Sidebar>
```

### With Badges

A count folded into an item's accessible name, and a second grouped section.

```svelte
<script lang="ts">
	import { Sidebar, SidebarGroup, SidebarItem, SidebarSeparator } from "fancy-ui-svelte";
</script>

<Sidebar>
	<SidebarGroup label="General">
		<SidebarItem sound href="#dashboard" current>Dashboard</SidebarItem>
		<SidebarItem sound href="#projects">Projects</SidebarItem>
		<SidebarItem sound href="#inbox" badge={4} badgeLabel="unread">Inbox</SidebarItem>
		<SidebarItem sound href="#settings">Settings</SidebarItem>
	</SidebarGroup>

	<SidebarSeparator />

	<SidebarGroup label="Danger zone">
		<SidebarItem sound href="#archived" badge="12">Archived</SidebarItem>
	</SidebarGroup>
</Sidebar>
```

### Collapsed

Icon-only rail — labels and badge meaning move to sr-only text, never removed.

```svelte
<script lang="ts">
	import { Sidebar, SidebarGroup, SidebarItem } from "fancy-ui-svelte";

	let collapsed = $state(true);
</script>

{#snippet dashboardIcon()}
	<svg
		class="size-4"
		viewBox="0 0 24 24"
		fill="none"
		stroke="currentColor"
		stroke-width="2"
		stroke-linecap="round"
		stroke-linejoin="round"
	>
		<rect x="3" y="3" width="7" height="9" rx="1" />
		<rect x="14" y="3" width="7" height="5" rx="1" />
		<rect x="14" y="12" width="7" height="9" rx="1" />
		<rect x="3" y="16" width="7" height="5" rx="1" />
	</svg>
{/snippet}

{#snippet inboxIcon()}
	<svg
		class="size-4"
		viewBox="0 0 24 24"
		fill="none"
		stroke="currentColor"
		stroke-width="2"
		stroke-linecap="round"
		stroke-linejoin="round"
	>
		<path d="M22 12h-6l-2 3h-4l-2-3H2" />
		<path
			d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11Z"
		/>
	</svg>
{/snippet}

{#snippet settingsIcon()}
	<svg
		class="size-4"
		viewBox="0 0 24 24"
		fill="none"
		stroke="currentColor"
		stroke-width="2"
		stroke-linecap="round"
		stroke-linejoin="round"
	>
		<circle cx="12" cy="12" r="3" />
		<path
			d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z"
		/>
	</svg>
{/snippet}

<div class="flex flex-col gap-3">
	<button
		type="button"
		class="border-border text-foreground w-fit rounded-[6px] border px-3 py-1.5 text-xs font-medium"
		onclick={() => (collapsed = !collapsed)}
	>
		{collapsed ? "Expand" : "Collapse"}
	</button>

	<Sidebar {collapsed}>
		<SidebarGroup label="General">
			<SidebarItem sound href="#dashboard" current icon={dashboardIcon}>Dashboard</SidebarItem>
			<SidebarItem sound href="#inbox" badge={4} badgeLabel="unread" icon={inboxIcon}
				>Inbox</SidebarItem
			>
			<SidebarItem sound href="#settings" icon={settingsIcon}>Settings</SidebarItem>
		</SidebarGroup>
	</Sidebar>
</div>
```

### With Footer

An avatar and name row, above a separator, pinned to the bottom.

```svelte
<script lang="ts">
	import { Sidebar, SidebarGroup, SidebarItem, SidebarFooter } from "fancy-ui-svelte";
</script>

<Sidebar>
	<SidebarGroup label="General">
		<SidebarItem sound href="#dashboard" current>Dashboard</SidebarItem>
		<SidebarItem sound href="#projects">Projects</SidebarItem>
		<SidebarItem sound href="#settings">Settings</SidebarItem>
	</SidebarGroup>

	<SidebarFooter>
		{#snippet avatar()}
			<span
				class="inline-block h-[22px] w-[22px] rounded-full bg-gradient-to-br from-purple-500 to-cyan-400"
			></span>
		{/snippet}
		Rama H.
	</SidebarFooter>
</Sidebar>
```
