ReScript Shadcn
Get started
  • Installation
Components
  • Accordion
  • Alert
  • AlertDialog
  • AspectRatio
  • Attachment
  • Avatar
  • Badge
  • Breadcrumb
  • Bubble
  • Button
  • ButtonGroup
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • ContextMenu
  • DataTable
  • DatePicker
  • Dialog
  • Direction
  • Drawer
  • DropdownMenu
  • Empty
  • Field
  • HoverCard
  • Input
  • InputGroup
  • InputOtp
  • Item
  • Kbd
  • Label
  • Marker
  • Menubar
  • Message
  • MessageScroller
  • NativeSelect
  • NavigationMenu
  • Pagination
  • Popover
  • Progress
  • RadioGroup
  • Resizable
  • ScrollArea
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • ToggleGroup
  • Tooltip
  • Typography

Sidebar

A composable, themeable and customizable sidebar component.

A sidebar that collapses to icons.

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.

Browse the Blocks Library.

Installation#

npx shadcn@latest add @rescript-shadcn/Sidebar

Structure#

A Sidebar component is composed of the following parts:

  • Sidebar.Provider - Handles collapsible state.
  • Sidebar - The sidebar container.
  • Sidebar.Header and Sidebar.Footer - Sticky at the top and bottom of the sidebar.
  • Sidebar.Content - Scrollable content.
  • Sidebar.Group - Section within the Sidebar.Content.
  • Sidebar.Trigger - Trigger for the Sidebar.
Sidebar Structure Sidebar Structure

Usage#

app/layout.res
 
module Layout = {
  @react.component 
  let make = (~children) => 
    <Sidebar.Provider>
      <AppSidebar />
      <main>
        <Sidebar.Trigger />
        {children}
      </main>
    </Sidebar.Provider>
}
components/AppSidebar.res
@react.component 
let make = () => 
  <Sidebar>
    <Sidebar.Header />
    <Sidebar.Content>
      <Sidebar.Group />
      <Sidebar.Group />
    </Sidebar.Content>
    <Sidebar.Footer />
  </Sidebar>

Sidebar.Provider#

The Sidebar.Provider component is used to provide the sidebar context to the Sidebar component. You should always wrap your application in a Sidebar.Provider component.

Props#

NameTypeDescription
defaultOpenboolDefault open state of the sidebar.
openboolOpen state of the sidebar (controlled).
onOpenChange(bool) => unitSets open state of the sidebar (controlled).

Width#

If you have a single sidebar in your application, you can use the sidebarWidth and sidebarWidthMobile variables in Sidebar.res to set the width of the sidebar.

components/ui/Sidebar.res
let sidebarWidth = "16rem"
let sidebarWidthMobile = "18rem"

For multiple sidebars in your application, you can use the --sidebar-width and --sidebar-width-mobile CSS variables in the style prop.

<Sidebar.Provider
  style={{
    "--sidebar-width": "20rem",
    "--sidebar-width-mobile": "20rem",
  }}
>
  <Sidebar />
</Sidebar.Provider>

Keyboard Shortcut#

To trigger the sidebar, you use the cmd+b keyboard shortcut on Mac and ctrl+b on Windows.

components/ui/Sidebar.res
let sidebarKeyboardShortcut = "b"

Sidebar#

The main Sidebar component used to render a collapsible sidebar.

Props#

PropertyTypeDescription
sideleft or rightThe side of the sidebar.
variantSidebar, Floating, or InsetThe variant of the sidebar.
collapsibleOffcanvas, Icon, or NotCollapsibleCollapsible state of the sidebar.
PropDescription
OffcanvasA collapsible sidebar that slides in from the left or right.
IconA sidebar that collapses to icons.
NotCollapsibleA non-collapsible sidebar.

Note: If you use the inset variant, remember to wrap your main content in a Sidebar.Inset component.

<Sidebar.Provider>
  <Sidebar variant=Inset />
  <Sidebar.Inset>
    <main>{children}</main>
  </Sidebar.Inset>
</Sidebar.Provider>

Sidebar.use#

The Sidebar.use hook is used to control the sidebar.

module AppSidebar = {
  @react.component 
  let make = () => {
    let {
      state,
      open,
      setOpen,
      openMobile,
      setOpenMobile,
      isMobile,
      toggleSidebar,
    } = Sidebar.use()
  }
}
PropertyTypeDescription
stateexpanded or collapsedThe current state of the sidebar.
openboolWhether the sidebar is open.
setOpen(bool) => unitSets the open state of the sidebar.
openMobileboolWhether the sidebar is open on mobile.
setOpenMobile(bool) => unitSets the open state of the sidebar on mobile.
isMobileboolWhether the sidebar is on mobile.
toggleSidebarunit => unitToggles the sidebar. Desktop and mobile.

Sidebar.Header#

Use the Sidebar.Header component to add a sticky header to the sidebar.

components/AppSidebar.res
<Sidebar>
  <Sidebar.Header>
    <Sidebar.Menu>
      <Sidebar.MenuItem>
        <DropdownMenu>
          <DropdownMenu.Trigger render={<Sidebar.MenuButton/>}>
              {"Select Workspace"->React.string}
              <Icons.ChevronDown className="ml-auto" />
          </DropdownMenu.Trigger>
          <DropdownMenu.Content className="w-[--radix-popper-anchor-width]">
            <DropdownMenu.Item>
              <span> {"Acme Inc"->React.string} </span>
            </DropdownMenu.Item>
          </DropdownMenu.Content>
        </DropdownMenu>
      </Sidebar.MenuItem>
    </Sidebar.Menu>
  </Sidebar.Header>
</Sidebar>

Sidebar.Footer#

Use the Sidebar.Footer component to add a sticky footer to the sidebar.

<Sidebar>
  <Sidebar.Footer>
    <Sidebar.Menu>
      <Sidebar.MenuItem>
        <Sidebar.MenuButton>
          <User2 /> Username
        </Sidebar.MenuButton>
      </Sidebar.MenuItem>
    </Sidebar.Menu>
  </Sidebar.Footer>
</Sidebar>

Sidebar.Content#

The Sidebar.Content component is used to wrap the content of the sidebar. This is where you add your Sidebar.Group components. It is scrollable.

<Sidebar>
  <Sidebar.Content>
    <Sidebar.Group />
    <Sidebar.Group />
  </Sidebar.Content>
</Sidebar>

Sidebar.Group#

Use the Sidebar.Group component to create a section within the sidebar.

A Sidebar.Group has a Sidebar.GroupLabel, a Sidebar.GroupContent and an optional Sidebar.GroupAction.

<Sidebar.Group>
  <Sidebar.GroupLabel>Application</Sidebar.GroupLabel>
  <Sidebar.GroupAction>
    <Plus /> <span className="sr-only">Add Project</span>
  </Sidebar.GroupAction>
  <Sidebar.GroupContent></Sidebar.GroupContent>
</Sidebar.Group>

To make a Sidebar.Group collapsible, wrap it in a Collapsible.

<Collapsible defaultOpen className="group/collapsible">
  <Sidebar.Group>
    <Sidebar.GroupLabel render={<Collapsible.Trigger/>}>
        {"Help"->React.string}
        <Icons.ChevronDown className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
    </Sidebar.GroupLabel>
    <Collapsible.Content>
      <Sidebar.GroupContent />
    </Collapsible.Content>
  </Sidebar.Group>
</Collapsible>

Sidebar.Menu#

The Sidebar.Menu component is used for building a menu within a Sidebar.Group.

Sidebar Menu Sidebar Menu
<Sidebar.Menu>
  {projects.map((project) => (
    <Sidebar.MenuItem key={project.name}>
      <Sidebar.MenuButton render={<a href={project.url}/>}>
        <Project.Icon />
        <span>{project.name->React.string}</span>
      </Sidebar.MenuButton>
    </Sidebar.MenuItem>
  ))}
</Sidebar.Menu>

Sidebar.MenuButton#

The Sidebar.MenuButton component is used to render a menu button within a Sidebar.MenuItem.

By default, the Sidebar.MenuButton renders a button but you can use the render prop to render a different component such as a Link or an a tag.

Use the isActive prop to mark a menu item as active.

<Sidebar.MenuButton render={<a href="#"/>} isActive>
  {"Home"->React.string}
</Sidebar.MenuButton>

Sidebar.MenuAction#

The Sidebar.MenuAction component is used to render a menu action within a Sidebar.MenuItem.

<Sidebar.MenuItem>
  <Sidebar.MenuButton render={<a href="#"/>}>
      <Home />
      <span> {"Home"->React.string} </span>
  </Sidebar.MenuButton>
  <Sidebar.MenuAction>
    <Icons.Plus /> <span className="sr-only">Add Project</span>
  </Sidebar.MenuAction>
</Sidebar.MenuItem>

Sidebar.MenuSub#

The Sidebar.MenuSub component is used to render a submenu within a Sidebar.Menu.

<Sidebar.MenuItem>
  <Sidebar.MenuButton />
  <Sidebar.MenuSub>
    <Sidebar.MenuSubItem>
      <Sidebar.MenuSubButton />
    </Sidebar.MenuSubItem>
  </Sidebar.MenuSub>
</Sidebar.MenuItem>

Sidebar.MenuBadge#

The Sidebar.MenuBadge component is used to render a badge within a Sidebar.MenuItem.

<Sidebar.MenuItem>
  <Sidebar.MenuButton />
  <Sidebar.MenuBadge>24</Sidebar.MenuBadge>
</Sidebar.MenuItem>

Sidebar.MenuSkeleton#

The Sidebar.MenuSkeleton component is used to render a skeleton for a Sidebar.Menu.

<Sidebar.Menu>
  {Array.fromInitializer(~length: 5 )->Array.mapWithIndex((_, index) => (
    <Sidebar.MenuItem key={index->Int.toString}>
      <Sidebar.MenuSkeleton />
    </Sidebar.MenuItem>
  ))}
</Sidebar.Menu>

Sidebar.Trigger#

Use the Sidebar.Trigger component to render a button that toggles the sidebar.

module CustomTrigger = {
  @react.component 
  let make = () => {
    let { toggleSidebar } = Sidebar.use()
 
    <button onClick={_ => toggleSidebar()}> {"Toggle Sidebar"->React.string} </button>
  }
}

Sidebar.Rail#

The Sidebar.Rail component is used to render a rail within a Sidebar. This rail can be used to toggle the sidebar.

<Sidebar>
  <Sidebar.Header />
  <Sidebar.Content>
    <Sidebar.Group />
  </Sidebar.Content>
  <Sidebar.Footer />
  <Sidebar.Rail />
</Sidebar>

Controlled Sidebar#

Use the open_ and onOpenChange props to control the sidebar.

module AppSidebar = {
  @react.component
  let make = () => {
    let (open_, setOpen) = React.useState(() => false)
 
    <Sidebar.Provider open_ onOpenChange={o => setOpen(_ => o)}>
      <Sidebar />
    </Sidebar.Provider>
  }
}

Theming#

We use the following CSS variables to theme the sidebar.

@layer base {
  :root {
    --sidebar-background: 0 0% 98%;
    --sidebar-foreground: 240 5.3% 26.1%;
    --sidebar-primary: 240 5.9% 10%;
    --sidebar-primary-foreground: 0 0% 98%;
    --sidebar-accent: 240 4.8% 95.9%;
    --sidebar-accent-foreground: 240 5.9% 10%;
    --sidebar-border: 220 13% 91%;
    --sidebar-ring: 217.2 91.2% 59.8%;
  }
 
  .dark {
    --sidebar-background: 240 5.9% 10%;
    --sidebar-foreground: 240 4.8% 95.9%;
    --sidebar-primary: 0 0% 98%;
    --sidebar-primary-foreground: 240 5.9% 10%;
    --sidebar-accent: 240 3.7% 15.9%;
    --sidebar-accent-foreground: 240 4.8% 95.9%;
    --sidebar-border: 240 3.7% 15.9%;
    --sidebar-ring: 217.2 91.2% 59.8%;
  }
}

Styling#

Here are some tips for styling the sidebar based on different states.

<Sidebar collapsible="icon">
  <Sidebar.Content>
    <Sidebar.Group className="group-data-[collapsible=icon]:hidden" />
  </Sidebar.Content>
</Sidebar>
<Sidebar.MenuItem>
  <Sidebar.MenuButton />
  <Sidebar.MenuAction className="peer-data-[active=true]/menu-button:opacity-100" />
</Sidebar.MenuItem>
Platform
    • History
    • Starred
    • Settings
Projects
  • Design Engineering
  • Sales & Marketing
  • Travel