# 侧边栏 Sidebar > 页面左边一列菜单,可以分组,可以折叠成只剩图标的一条。 分类:导航 [全部组件和流程](https://www.dachuiai.com/llms.txt) · [导航选型规则](https://www.dachuiai.com/guides/navigation.md) ## 给 AI:用户把这个组件发给了你 1. 先看用户的项目:框架、页面类型、现在的风格、手机还是电脑为主。 2. 对照下面的「适合 / 不适合」判断合不合适。不合适就直接说,并从[导航选型规则](https://www.dachuiai.com/guides/navigation.md)或[全部组件](https://www.dachuiai.com/llms.txt)里另挑一个。 3. 合适就按「装进项目」装好,示例里的文字和图片换成用户自己的。 4. 告诉用户用了什么、放在哪个文件、以后想改快慢、颜色、大小改哪个参数。 ## 什么时候用 - 适合:后台、管理系统、软件登录后的工具界面,菜单 6 项以上。 - 不适合:官网、电商这类前台(用顶部导航);手机(换成汉堡菜单或底部标签栏)。 - 适合的网站:后台、SaaS - 放在:导航 - 手机上:要改:手机上收起来,用汉堡菜单打开,或者换成底部标签栏。 - 性能代价:低:折叠时宽度过渡 0.25 秒。 - 常搭配:[面包屑 Breadcrumb](https://www.dachuiai.com/c/breadcrumb.md)、[标签页 Tabs](https://www.dachuiai.com/c/tabs.md)、[分页 Pagination](https://www.dachuiai.com/c/pagination.md) ## 装进项目 - 写法:React 18 以上 + TypeScript + Tailwind CSS v4,一个文件就能用,不引用别的组件。 - 依赖:`npm i lucide-react` - 文件:原样存成 `sidebar.tsx`(比如 `src/components/sidebar.tsx`)。能跑命令就下载[原文](https://www.dachuiai.com/code/sidebar.tsx),比手抄准:`curl -fsSL -o src/components/sidebar.tsx https://www.dachuiai.com/code/sidebar.tsx`(Windows 写 `curl.exe`)。下载完看一眼第一行是 `import`,不是网页。 - 导出:`Sidebar` 是可以直接用的部分;最后的 `export default` 是演示示例,只作参考。 - 注意:groups 是分组的菜单数据(每组 title 和 items,每项 key、label、icon,可带 badge),active 是当前项,onSelect 切换;折叠状态在组件里面。 - 保留代码里 `prefers-reduced-motion` 的处理:用户开了「减弱动态效果」时内容照样完整显示。 - Next.js(有 app 文件夹):文件第一行加 `'use client';`。 - 用 JavaScript 不用 TypeScript:Vite 和 Next.js 都能直接用 .tsx 文件;也可以删掉类型标注,改名 .jsx。 - 没有 Tailwind:先装 Tailwind CSS v4(Vite 项目 `npm i tailwindcss @tailwindcss/vite`,vite 配置的 plugins 里加 `tailwindcss()`,入口引入的那个 CSS 文件(一般是 `src/index.css`)第一行写 `@import "tailwindcss";`),或者把类名改写成项目用的样式。 - 已经装了 Tailwind v3:别为了一个组件升级。类名大多通用,少数 v4 写法要换,比如焦点框 `outline-2` 在 v3 里要写成 `outline outline-2`。 - 不是 React(Vue、Svelte、小程序、纯 HTML):照着代码的做法改写,时长、曲线、参数保持一样。Wix、有赞这类建站平台装不进代码,告诉用户去平台自带的动效设置里找。 ## 参数 | 参数 | 默认值 | 作用 | | --- | --- | --- | | `groups` | | 分组的菜单:每组 title 和 items | | `active` | | 当前选中的那一项(key) | | `onSelect` | | 点某一项时调用,参数是它的 key | ## 你可以说 > 后台加 Sidebar 侧边栏,菜单分组;侧边栏可以折叠,折叠后只显示图标,鼠标放上去显示名字。 ## 完整代码 ```tsx import {useState, type ComponentType} from 'react'; import { BarChart3, ChevronsLeft, LayoutDashboard, Megaphone, Package, Settings, ShoppingCart, Ticket, Users, } from 'lucide-react'; /* --------------------------------------------------------------- * Sidebar 侧边栏 * 竖着放在页面左边的一列菜单,后台系统最常见。菜单多了就分组; * 点底部按钮可以折叠成只剩图标的一条,鼠标放上去(或键盘聚焦)显示名字。 * ------------------------------------------------------------- */ type Icon = ComponentType<{size?: number; strokeWidth?: number; className?: string}>; export type NavGroup = {title: string; items: {key: string; label: string; icon: Icon; badge?: number}[]}; export function Sidebar({groups, active, onSelect}: {groups: NavGroup[]; active: string; onSelect: (k: string) => void}) { const [collapsed, setCollapsed] = useState(false); return ( ); } /* ---------------- 示例:「山野」商家后台 ---------------- */ const GROUPS: NavGroup[] = [ {title: '概览', items: [{key: 'dash', label: '仪表盘', icon: LayoutDashboard}, {key: 'stats', label: '数据分析', icon: BarChart3}]}, {title: '商品与订单', items: [{key: 'orders', label: '订单', icon: ShoppingCart, badge: 12}, {key: 'goods', label: '商品', icon: Package}, {key: 'members', label: '会员', icon: Users}]}, {title: '运营', items: [{key: 'coupons', label: '优惠券', icon: Ticket}, {key: 'promo', label: '活动', icon: Megaphone}, {key: 'settings', label: '设置', icon: Settings}]}, ]; const TITLES: Record = Object.fromEntries(GROUPS.flatMap((g) => g.items.map((i) => [i.key, i.label]))); const BARS = [32, 45, 38, 52, 48, 66, 58, 72, 64, 80, 76, 92]; export default function SidebarDemo() { const [active, setActive] = useState('dash'); return (

{TITLES[active]}

{[['今日订单', '128', '+12%'], ['今日销售额', '¥36,820', '+8.4%'], ['新会员', '42', '+5']].map(([k, v, d]) => (
{k}
{v}
{d}
))}
近 12 周销售额
{BARS.map((h, i) => (
))}
); } ```