App Shell
AppShell là khung của ứng dụng: sidebar thu về icon hoặc mở thành Drawer, thanh trên cùng và nội dung chính.
breakpoint (container query, theo độ rộng khung chứ không theo màn hình) sidebar nằm trong bố cục và SidebarTrigger thu nó về rail chỉ còn icon, tên mục hiện trong Tooltip. Hẹp hơn, cùng nội dung mở trong Drawer: theo một link hoặc chọn một mục Nav là Drawer đóng, focus quay về nút đã mở. Ctrl+B (⌘B) làm việc giống SidebarTrigger, trừ khi đang gõ trong ô nhập hoặc bằng bộ gõ; trang có nhiều AppShell (như trang này) thì chỉ khung đang được focus hoặc vừa được bấm vào nhận phím. persistKey lưu trạng thái thu gọn (và độ rộng) vào cookie; Drawer không bao giờ được lưu. Render ở server: đọc cookie bằng readAppShellCookie(cookieHeader, key) rồi truyền defaultCollapsed để không nháy. AppShell là container tên app-shell: phần nào cần theo độ rộng khung thì dùng @3xl/app-shell:…. Chiều cao thanh trên cùng đổi qua biến --app-shell-header (mặc định 3.5rem), SidebarHeader và các phần dính theo cùng biến. Nút SidebarTrigger có Tooltip mang nhãn và phím tắt. Các demo dưới đây nằm trong trang docs nên AppShellMain dùng asChild với div (một trang chỉ có một <main>).Import
Cài từ npm, chép mã nguồn vào dự án bằng @yugen-ui/cli hoặc shadcn CLI, hoặc import thẳng khi làm việc trong repo này.
// npm install yugen-uiimport { AppShell, AppShellHeader, AppShellMain, AppShellAside, AppShellFooter, Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarGroup, SidebarTrigger, SidebarRail, useAppShell, readAppShellCookie,} from "yugen-ui";Biến thể
Mỗi ô là một mẫu độc lập: hover để Copy, hoặc bấm Code để xem mã nguồn.
Khung hẹp
Hẹp hơn breakpoint, SidebarTrigger mở sidebar trong Drawer. Chọn một mục là Drawer đóng.
Khung từ 42rem: sidebar nằm trong bố cục.
Đổi breakpoint
breakpoint="2xl" (42rem). Mốc đo theo độ rộng của AppShell chứ không theo màn hình: kéo góc dưới của khung để thử. Qua mốc khi Drawer đang mở thì Drawer đóng, focus về SidebarTrigger, nút bị ẩn thì về nội dung; trạng thái thu gọn giữ nguyên. Phần tự làm cần đổi cùng lúc thì dùng @2xl/app-shell:…, hoặc useAppShell().narrow cho hành vi (luôn là false khi render ở server). md: và useMediaQuery theo màn hình nên sẽ lệch mốc.
Sidebar + cột phụ
AppShellAside nằm bên phải nội dung, chỉ hiện từ breakpoint. Trên màn hẹp, đưa nội dung của nó vào Sheet hoặc một trang riêng.
Trang nội dung: cả trang cuộn
Không có Sidebar, cột của nó rộng 0. scroll="page" cho site nội dung (blog, cửa hàng, landing): cả trang cuộn, thanh trên cùng dính lại, AppShellFooter ở cuối trang. Trong một vùng tự cuộn như khung này, vùng đó thay cho cửa sổ.
Thanh trên cùng trải ngang
layout="header": thanh trên cùng (logo, tìm kiếm, tài khoản) trải hết chiều ngang, sidebar nằm bên dưới. Hợp với trang quản trị.
Ẩn hẳn sidebar & useAppShell
collapsible="offcanvas" cho danh sách không có icon (hội thoại, tệp): thu gọn là ẩn hẳn. Nút trong sidebar không phải link thì tự đóng Drawer bằng useAppShell().
Cách dùng
- Đặt AppShell ở gốc ứng dụng, cao bằng màn hình; nội dung cuộn trong AppShellMain.
- Mỗi NavItem trong sidebar có icon khi dùng collapsible="icon", để rail vẫn dùng được.
- Dùng persistKey để người dùng mở lại ứng dụng vẫn thấy sidebar như lần trước.
- Không đặt phần tử khác ngoài các phần của AppShell trực tiếp trong AppShell: lưới sẽ xếp nó vào ô trống.
- Không lồng AppShellMain (thẻ <main>) trong một trang đã có <main>; dùng asChild với div.
- Không đổi Ctrl+B sang phím trùng phím tắt của trình duyệt hay của ô soạn thảo.
Props
| Prop · Kiểu | Mặc định | Mô tả |
|---|---|---|
| breakpoint"lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | Mặc định: "4xl" | Độ rộng của AppShell (không phải màn hình) từ đó sidebar nằm trong bố cục và AppShellAside hiện: 32 / 36 / 42 / 48 / 56 / 64rem, trùng mốc container query @lg … @5xl. Hẹp hơn là Drawer. |
| layout"sidebar" | "header" | Mặc định: "sidebar" | sidebar: sidebar cao hết khung, thanh trên cùng bên cạnh. header: thanh trên cùng trải ngang, sidebar bên dưới. |
| scroll"main" | "page" | Mặc định: "main" | main: khung cao bằng màn hình, AppShellMain tự cuộn (ứng dụng). page: cả trang cuộn, thanh trên cùng và sidebar dính lại (site nội dung). |
| collapsed / defaultCollapsedboolean | Mặc định: false | Sidebar thu gọn trên màn rộng. |
| onCollapsedChange(collapsed: boolean) => void | Mặc định: — | Gọi khi thu gọn / mở rộng. |
| persistKeystring | Mặc định: — | Tên cookie lưu trạng thái thu gọn và độ rộng; giá trị đã lưu thắng defaultCollapsed, cookie thiếu hoặc hỏng thì dùng defaultCollapsed. Chỉ gồm chữ, số, _ và -: tên khác thì không lưu gì (có cảnh báo khi phát triển). Cookie chỉ chứa collapsed hoặc expanded, kèm độ rộng (px) khi Sidebar resizable đã được kéo. Cookie đặt ở path=/ với samesite=lax, thêm secure trên https, nên mỗi ứng dụng cùng domain cần một tên riêng. |
| shortcutstring | false | Mặc định: "b" | Phím đi cùng Ctrl / ⌘; false để tắt. Nhiều AppShell trên một trang: chỉ khung đang được focus hoặc vừa được bấm vào nhận phím. |
| skipLinkboolean | Mặc định: true | Link “Chuyển tới nội dung” hiện khi được focus. |
| Sidebar | Mặc định: "icon" | Thu về rail chỉ icon, ẩn hẳn, hoặc luôn mở. |
| Sidebar | Mặc định: false | SidebarRail thành thanh chia kéo đổi độ rộng (mũi tên, Home / End, Enter thu gọn). |
| Sidebar | Mặc định: 256 / 200 / 400 | Độ rộng khi mở, px. |
| Sidebar | Mặc định: — | Tên của Drawer trên màn hẹp. |
| SidebarGroup | Mặc định: — | Tên nhóm; trong rail chỉ còn cho trình đọc màn hình. |
| AppShellHeader / AppShellMain / AppShellAside / AppShellFooter | Mặc định: — | Đổi thẻ header / main / aside / footer sang phần tử con. |
| useAppShell | Mặc định: — | narrow, collapsed, setCollapsed, drawerOpen, setDrawerOpen, toggleSidebar, rail. |
| readAppShellCookie | Mặc định: — | Đọc trạng thái đã lưu từ document.cookie hoặc header Cookie khi render ở server. Gọi được trong Server Component khi import từ yugen-ui (gốc gói). |
Messages
Chữ có sẵn của component: nhãn, aria-label, thông báo cho trình đọc màn hình.
Mặc định là tiếng Anh. Đổi qua prop messages của YugenProvider, theo namespace bên dưới; messagesVi chứa bản tiếng Việt. Xem Ngôn ngữ giao diện.
messages.appShell
| Khoá · Kiểu | Mặc định (tiếng Anh) | messagesVi |
|---|---|---|
| skipToContentstring Skip link đầu trang, tới AppShellMain. | Mặc định (tiếng Anh)"Skip to content" | messagesVi"Chuyển tới nội dung" |
| sidebarstring Tên của Drawer chứa sidebar trên màn hẹp. | Mặc định (tiếng Anh)"Sidebar" | messagesVi"Thanh bên" |
| openSidebarstring SidebarTrigger trên màn hẹp. | Mặc định (tiếng Anh)"Open sidebar" | messagesVi"Mở thanh bên" |
| collapseSidebarstring SidebarTrigger và SidebarRail trên màn rộng. | Mặc định (tiếng Anh)"Collapse sidebar" | messagesVi"Thu gọn thanh bên" |
| expandSidebarstring | Mặc định (tiếng Anh)"Expand sidebar" | messagesVi"Mở rộng thanh bên" |
| resizeSidebarstring Thanh chia kéo đổi độ rộng (Sidebar | Mặc định (tiếng Anh)"Resize sidebar" | messagesVi"Đổi độ rộng thanh bên" |