Sidebar with motion: it springs its width as it folds, the current page's highlight and the hover glide from row to row, and sections open on a gliding height.
$ pnpm dlx shadcn@latest add https://dashral.com/r/motion-sidebar.jsonInstallation
$ pnpm dlx shadcn@latest add https://dashral.com/r/motion-sidebar.jsonAdds components/dashral/motion/sidebar.tsx, the Sidebar it builds on (in components/dashral/), motion and the motion files every motion component shares. With the registry in your components.json:
$ pnpm dlx shadcn@latest add @dashral/motion-sidebarUsage
The same as Sidebar, imported from components/dashral/motion/: swap the import and it moves.
import { Sidebar } from "@/components/dashral/motion/sidebar"
<Sidebar header={<Logo />} items={items} linkAs={Link} />Examples
Compared with Default
The width and the current page's highlight slide in CSS; sections open on their height; hover jumps from row to row.
Motion
The width springs as it folds while the labels fade away; the current page's highlight and the hover each glide from row to row without a blink; sections open with their links rising in.
How the two editions differ in general, and which to use where: Motion.
API reference
Every prop of Sidebar, and every attribute of the element it renders. The Motion edition adds no props of its own.
Sidebar
Also takes every prop of <aside>(opens in a new tab).
| Prop | Type | Default |
|---|---|---|
items | SidebarItem[]Required. Links ({ label, icon, href, active, badge, children }), groups ({ type: "group", label, items }) and separators. | — |
header | ReactNodeAt the top: a logo, a workspace switcher. | — |
footer | ReactNodeAt the bottom: the signed-in user, a help link. | — |
collapsed / defaultCollapsed / onCollapsedChange | booleanNarrowed to its icons. Controlled, or initial with the toggle changing it. | false |
collapsible | booleanThe collapse toggle at the bottom. | true |
linkAs | ElementTypeYour router's link, for items with href. | "a" |
aria-label | stringNames the navigation (translated by default). | "Navigation" |
classNames | { header, nav, footer, item }Classes for each part. | — |
className | stringExtra classes, merged with cn() so yours win. | — |
SidebarLink
= { label: string; icon?: ReactNode; href?: string; onSelect?: () => void; active?: boolean; badge?: ReactNode; disabled?: boolean; children?: SidebarLink[]; defaultOpen?: boolean }Motion
- Folding, the width springs from 240px to 60px with no overshoot; the labels fade as they slide 8px away, and come back a moment after it widens. The icons never move: they sit where the narrow sidebar's middle is.
- The current page's highlight is one element gliding from row to row with a touch of overshoot (motion's shared layout).
- The hover is one soft pill gliding after the pointer without going out between rows; it fades only when the pointer leaves the list.
- A section opens and closes on a gliding height, its chevron turning on a spring and its links rising in, 30ms apart.
- Collapsed, rows name themselves in motion tooltips and a section opens its links in a motion menu. With reduced motion everything changes at once.