- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Card
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Dialog
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- Native Select
- Pagination
- Popover
- Progress
- Radio Group
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
- Typography
Sidebars are one of the most complex components to build. They are central to any application and often contain a lot of moving parts.
We now have a solid foundation to build on top of. Composable. Themeable. Customizable.
Installation#
pnpm dlx shadcn@latest add @force-ui-ember/sidebar
Usage#
import {
SidebarProvider,
SidebarTrigger,
} from '@/ember-ui/sidebar';
import { AppSidebar } from '@/components/app-sidebar';
<template>
<SidebarProvider>
<AppSidebar />
<main>
<SidebarTrigger />
{{yield}}
</main>
</SidebarProvider>
</template>import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
} from '@/ember-ui/sidebar';
<template>
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
</Sidebar>
</template>Composition#
Use the following composition to build a Sidebar layout:
SidebarProvider
├── Sidebar
│ ├── SidebarHeader
│ ├── SidebarContent
│ │ ├── SidebarGroup
│ │ │ ├── SidebarGroupLabel
│ │ │ ├── SidebarGroupAction
│ │ │ ├── SidebarGroupContent
│ │ │ └── SidebarMenu
│ │ │ ├── SidebarMenuItem
│ │ │ │ ├── SidebarMenuButton
│ │ │ │ ├── SidebarMenuAction
│ │ │ │ └── SidebarMenuBadge
│ │ │ └── SidebarMenuItem
│ │ │ ├── SidebarMenuButton
│ │ │ └── SidebarMenuSub
│ │ │ ├── SidebarMenuSubItem
│ │ │ └── SidebarMenuSubItem
│ │ └── SidebarGroup
│ │ └── SidebarMenu
│ │ ├── SidebarMenuItem
│ │ └── SidebarMenuItem
│ ├── SidebarFooter
│ └── SidebarRail
├── SidebarInset
└── SidebarTriggerStructure#
- SidebarProvider — Handles collapsible state and provides sidebar context to child components.
- Sidebar — The main collapsible sidebar panel.
- SidebarHeader — Sticky at the top; use for branding, titles, or workspace switchers.
- SidebarFooter — Sticky at the bottom; use for user menus, settings, or actions.
- SidebarContent — Scrollable region between the header and footer.
- SidebarGroup — Groups related navigation with optional label, action, and content areas.
- SidebarMenu / SidebarMenuItem — Menu structure for links, badges, actions, and nested submenus.
- SidebarRail — Resize handle for adjusting sidebar width when applicable.
- SidebarInset — Wraps main content when using the
insetvariant. - SidebarTrigger — Control that toggles the sidebar open or collapsed.
SidebarProvider#
The SidebarProvider component is used to provide the sidebar context to the Sidebar component. You should always wrap your application in a SidebarProvider component.
Arguments#
| Name | Type | Description |
|---|---|---|
@defaultOpen | boolean | Default open state of the sidebar. |
@open | boolean | Open state of the sidebar (controlled). |
@onOpenChange | (open: boolean) => void | Sets open state of the sidebar (controlled). |
Width#
If you have a single sidebar in your application, you can use the SIDEBAR_WIDTH and SIDEBAR_WIDTH_MOBILE variables in sidebar.gts to set the width of the sidebar.
const SIDEBAR_WIDTH = "16rem"
const SIDEBAR_WIDTH_MOBILE = "18rem"For multiple sidebars in your application, you can use the @style argument to set the width of the sidebar.
<SidebarProvider @style="--sidebar-width: 20rem; --sidebar-width-mobile: 20rem">
<Sidebar />
</SidebarProvider>Keyboard Shortcut#
To trigger the sidebar, you use the cmd+b keyboard shortcut on Mac and ctrl+b on Windows.
const SIDEBAR_KEYBOARD_SHORTCUT = "b"Sidebar#
The main Sidebar component used to render a collapsible sidebar.
Arguments#
| Property | Type | Description |
|---|---|---|
@side | left or right | The side of the sidebar. |
@variant | sidebar, floating, or inset | The variant of the sidebar. |
@collapsible | offcanvas, icon, or none | Collapsible state of the sidebar. |
| Prop | Description |
|---|---|
offcanvas | A collapsible sidebar that slides in from the left or right. |
icon | A sidebar that collapses to icons. |
none | A non-collapsible sidebar. |
Note: If you use the inset variant, remember to wrap your main content
in a SidebarInset component.
<SidebarProvider>
<Sidebar @variant="inset" />
<SidebarInset>
<main>{{yield}}</main>
</SidebarInset>
</SidebarProvider>useSidebar#
The useSidebar hook is used to control the sidebar. Since this is Ember, you need to use the context via ember-provide-consume-context:
import { consume } from 'ember-provide-consume-context';
const SidebarContext = 'sidebar-context';
class MyComponent extends Component {
@consume(SidebarContext) sidebar;
handleToggle = () => {
this.sidebar.toggleSidebar();
};
}| Property | Type | Description |
|---|---|---|
state | expanded or collapsed | The current state of the sidebar. |
open | boolean | Whether the sidebar is open. |
setOpen | (open: boolean) => void | Sets the open state of the sidebar. |
openMobile | boolean | Whether the sidebar is open on mobile. |
setOpenMobile | (open: boolean) => void | Sets the open state of the sidebar on mobile. |
isMobile | boolean | Whether the sidebar is on mobile. |
toggleSidebar | () => void | Toggles the sidebar. Desktop and mobile. |
SidebarHeader#
Use the SidebarHeader component to add a sticky header to the sidebar.
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/ember-ui/dropdown-menu';
import {
Sidebar,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from '@/ember-ui/sidebar';
import ChevronDown from '~icons/ms/keyboard_arrow_down';
<template>
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger>
<SidebarMenuButton>
Select Workspace
<ChevronDown class="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-[--radix-popper-anchor-width]">
<DropdownMenuItem>
<span>Acme Inc</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
</Sidebar>
</template>SidebarFooter#
Use the SidebarFooter component to add a sticky footer to the sidebar.
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/ember-ui/dropdown-menu';
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from '@/ember-ui/sidebar';
import ChevronUp from '~icons/ms/keyboard_arrow_up';
import User2 from '~icons/ms/person';
<template>
<Sidebar>
<SidebarHeader />
<SidebarContent />
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger>
<SidebarMenuButton>
<User2 /> Username
<ChevronUp class="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent @side="top" class="w-[--radix-popper-anchor-width]">
<DropdownMenuItem>
<span>Account</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Billing</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Sign out</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
</template>SidebarContent#
The SidebarContent component is used to wrap the content of the sidebar. This is where you add your SidebarGroup components. It is scrollable.
import { Sidebar, SidebarContent, SidebarGroup } from '@/ember-ui/sidebar';
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
</Sidebar>
</template>SidebarGroup#
Use the SidebarGroup component to create a section within the sidebar.
A SidebarGroup has a SidebarGroupLabel, a SidebarGroupContent and an optional SidebarGroupAction.
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
} from '@/ember-ui/sidebar';
import Plus from '~icons/ms/add';
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Application</SidebarGroupLabel>
<SidebarGroupAction title="Add Project">
<Plus />
<span class="sr-only">Add Project</span>
</SidebarGroupAction>
<SidebarGroupContent />
</SidebarGroup>
</SidebarContent>
</Sidebar>
</template>To make a SidebarGroup collapsible, wrap it in a Collapsible.
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/ember-ui/collapsible';
import {
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
} from '@/ember-ui/sidebar';
import ChevronDown from '~icons/ms/keyboard_arrow_down';
<template>
<Collapsible @defaultOpen={{true}} class="group/collapsible">
<SidebarGroup>
<SidebarGroupLabel @asChild={{true}}>
<CollapsibleTrigger>
Help
<ChevronDown
class="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180"
/>
</CollapsibleTrigger>
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent />
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
</template>SidebarGroupAction#
Use the SidebarGroupAction component to add an action button to the SidebarGroup.
import {
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
} from '@/ember-ui/sidebar';
import Plus from '~icons/ms/add';
<template>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupAction title="Add Project">
<Plus />
<span class="sr-only">Add Project</span>
</SidebarGroupAction>
<SidebarGroupContent />
</SidebarGroup>
</template>SidebarMenu#
The SidebarMenu component is used for building a menu within a SidebarGroup.
A SidebarMenu component is composed of SidebarMenuItem, SidebarMenuButton, SidebarMenuAction and SidebarMenuSub components.
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from '@/ember-ui/sidebar';
const projects = [
{ name: 'Design Engineering', url: '#', icon: Frame },
{ name: 'Sales & Marketing', url: '#', icon: PieChart },
{ name: 'Travel', url: '#', icon: Map },
];
<template>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Projects</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{{#each projects as |project|}}
<SidebarMenuItem>
<SidebarMenuButton>
<a href={{project.url}}>
<project.icon />
<span>{{project.name}}</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
{{/each}}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</template>SidebarMenuButton#
The SidebarMenuButton component is used to render a menu button within a SidebarMenuItem.
By default, the SidebarMenuButton renders a button but you should yield to it to render a different element such as a LinkTo or an a tag.
Use the @isActive argument to mark a menu item as active.
<SidebarMenuButton @isActive={{true}}>
<a href="#">Home</a>
</SidebarMenuButton>SidebarMenuAction#
The SidebarMenuAction component is used to render a menu action within a SidebarMenuItem.
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/ember-ui/dropdown-menu';
import {
SidebarMenuAction,
SidebarMenuButton,
SidebarMenuItem,
} from '@/ember-ui/sidebar';
import Home from '~icons/ms/home';
import MoreHorizontal from '~icons/ms/more_horiz';
<template>
<SidebarMenuItem>
<SidebarMenuButton>
<a href="#">
<Home />
<span>Home</span>
</a>
</SidebarMenuButton>
<DropdownMenu>
<DropdownMenuTrigger>
<SidebarMenuAction>
<MoreHorizontal />
</SidebarMenuAction>
</DropdownMenuTrigger>
<DropdownMenuContent @side="right" @align="start">
<DropdownMenuItem>
<span>Edit Project</span>
</DropdownMenuItem>
<DropdownMenuItem>
<span>Delete Project</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</template>SidebarMenuSub#
The SidebarMenuSub component is used to render a submenu within a SidebarMenu.
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuSub>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
</SidebarMenuSub>
</SidebarMenuItem>Collapsible SidebarMenu#
To make a SidebarMenu component collapsible, wrap it and the SidebarMenuSub components in a Collapsible.
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/ember-ui/collapsible';
import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubItem,
} from '@/ember-ui/sidebar';
<template>
<SidebarMenu>
<Collapsible @defaultOpen={{true}} class="group/collapsible">
<SidebarMenuItem>
<CollapsibleTrigger>
<SidebarMenuButton />
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
<SidebarMenuSubItem />
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
</SidebarMenu>
</template>SidebarMenuBadge#
The SidebarMenuBadge component is used to render a badge within a SidebarMenuItem.
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>SidebarMenuSkeleton#
The SidebarMenuSkeleton component is used to render a skeleton for a SidebarMenu. You can use this to show a loading state.
import {
SidebarMenu,
SidebarMenuItem,
SidebarMenuSkeleton,
} from '@/ember-ui/sidebar';
<template>
<SidebarMenu>
{{#each (array 1 2 3 4 5) as |_|}}
<SidebarMenuItem>
<SidebarMenuSkeleton />
</SidebarMenuItem>
{{/each}}
</SidebarMenu>
</template>SidebarTrigger#
Use the SidebarTrigger component to render a button that toggles the sidebar.
The SidebarTrigger component must be used within a SidebarProvider.
<SidebarProvider>
<Sidebar />
<main>
<SidebarTrigger />
</main>
</SidebarProvider>SidebarRail#
The SidebarRail component is used to render a rail within a Sidebar. This rail can be used to toggle the sidebar.
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
<SidebarRail />
</Sidebar>Controlled Sidebar#
Use the @open and @onOpenChange arguments to control the sidebar.
import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';
import { Sidebar, SidebarProvider } from '@/ember-ui/sidebar';
export default class extends Component {
@tracked open = false;
setOpen = (value) => {
this.open = value;
};
<template>
<SidebarProvider @open={{this.open}} @onOpenChange={{this.setOpen}}>
<Sidebar />
</SidebarProvider>
</template>
}Theming#
We use the following CSS variables to theme the sidebar. Add them to your app.css:
@layer base {
:root {
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.439 0 0);
}
}Styling#
Here are some tips for styling the sidebar based on different states.
<Sidebar @collapsible="icon">
<SidebarContent>
<SidebarGroup class="group-data-[collapsible=icon]:hidden" />
</SidebarContent>
</Sidebar><SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuAction class="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>API Reference#
SidebarProvider#
| Argument | Type | Description |
|---|---|---|
@defaultOpen | boolean | Default open state of the sidebar. |
@open | boolean | Open state of the sidebar (controlled). |
@onOpenChange | (open: boolean) => void | Sets open state of the sidebar (controlled). |
Sidebar#
| Argument | Type | Description |
|---|---|---|
@side | left or right | The side of the sidebar. |
@variant | sidebar, floating, or inset | The variant of the sidebar. |
@collapsible | offcanvas, icon, or none | Collapsible state of the sidebar. |
SidebarMenuButton#
| Argument | Type | Description |
|---|---|---|
@isActive | boolean | Whether the menu item is active. |
@size | default or sm or lg | The size of the button. |
@tooltip | string | Tooltip shown when sidebar is collapsed. |
On This Page
InstallationUsageCompositionStructureSidebarProviderArgumentsWidthKeyboard ShortcutSidebarArgumentsuseSidebarSidebarHeaderSidebarFooterSidebarContentSidebarGroupSidebarGroupActionSidebarMenuSidebarMenuButtonSidebarMenuActionSidebarMenuSubCollapsible SidebarMenuSidebarMenuBadgeSidebarMenuSkeletonSidebarTriggerSidebarRailControlled SidebarThemingStylingAPI ReferenceSidebarProviderSidebarSidebarMenuButton