AppSidebar
A ChatGPT-style collapsible app sidebar. Animates between full-width and icon rail. Logo click expands; collapse button only appears when open. Wrap the layout in AppSidebarProvider and use AppSidebarInset to shift main content.
Installation
# Install @opencosmos/ui to use AppSidebar
pnpm add @opencosmos/uiPreview
Loading preview...
Customize
— Icon element always visible (32×32). Clicking it toggles open/closed.
— Wordmark shown to the right of the logo when expanded.
Usage
Import
import { AppSidebar } from '@opencosmos/ui';Example
<AppSidebar>
Content
</AppSidebar>Eject
Copy this component into your project for full customization
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| logo | text | "" | Icon element always visible (32×32). Clicking it toggles open/closed. |
| title | text | "OpenCosmos" | Wordmark shown to the right of the logo when expanded. |
Accessibility
- Uses <aside> as the root element.
- Collapse button has aria-label="Collapse sidebar".
- Logo button aria-label describes the action (expand or app name).
- Nav items in collapsed state use title + aria-label for tooltip and screen reader.
- tabIndex={-1} on the collapse button when hidden prevents keyboard access to invisible controls.
- All transitions are gated by useMotionPreference — intensity 0 gives instant transitions.
Examples
Collapsible Sidebar
Sign-in Prompt (signed-out)
Code Examples
Full Layout
AppSidebarProvider manages open/close state (persisted in localStorage). AppSidebarInset shifts the main content in sync with the sidebar width.
import {
AppSidebarProvider, AppSidebar, AppSidebarInset, OpenCosmosIcon
} from '@opencosmos/ui';
import { MessageSquare, BookOpen } from 'lucide-react';
export default function AppLayout({ children }) {
return (
<AppSidebarProvider defaultOpen={true}>
<AppSidebar
logo={<OpenCosmosIcon size={18} />}
title="OpenCosmos"
items={[
{ icon: <MessageSquare className="w-4 h-4" />, label: 'Dialog', href: '/dialog' },
{ icon: <BookOpen className="w-4 h-4" />, label: 'Knowledge', href: '/knowledge' },
]}
footer={<AuthButton />}
/>
<AppSidebarInset>
{children}
</AppSidebarInset>
</AppSidebarProvider>
);
}Accessing state in children
useAppSidebar() gives any descendant access to the sidebar state.
import { useAppSidebar } from '@opencosmos/ui';
function MyHeader() {
const { isOpen, toggle } = useAppSidebar();
return <button onClick={toggle}>{isOpen ? 'Collapse' : 'Expand'}</button>;
}