@tailor-platform/app-shell 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/app-shell-core.css +1 -1
  2. package/dist/app-shell.d.ts +208 -114
  3. package/dist/app-shell.js +3449 -3446
  4. package/dist/{appshell-DLVBFo5J.js → appshell-B0wh5Lq0.js} +625 -512
  5. package/dist/style-entry.d.ts +116 -96
  6. package/dist/testing.d.ts +116 -96
  7. package/dist/testing.js +1 -1
  8. package/dist/vite-plugin.d.ts +116 -96
  9. package/package.json +8 -8
  10. package/skills/app-shell-patterns/SKILL.md +101 -14
  11. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
  12. package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
  13. package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
  14. package/skills/app-shell-patterns/references/api/define-module.md +247 -0
  15. package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
  16. package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
  17. package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
  18. package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
  19. package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
  20. package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
  21. package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
  22. package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
  23. package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
  24. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +126 -0
  25. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +146 -0
  26. package/skills/app-shell-patterns/references/api/use-app-shell.md +143 -0
  27. package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
  28. package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
  29. package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
  30. package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
  31. package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
  32. package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
  33. package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
  34. package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
  35. package/skills/app-shell-patterns/references/api/use-toast.md +107 -0
  36. package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
  37. package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
  38. package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
  39. package/skills/app-shell-patterns/references/components/alert.md +202 -0
  40. package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
  41. package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
  42. package/skills/app-shell-patterns/references/components/attachment.md +138 -0
  43. package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
  44. package/skills/app-shell-patterns/references/components/avatar.md +80 -0
  45. package/skills/app-shell-patterns/references/components/badge.md +309 -0
  46. package/skills/app-shell-patterns/references/components/button.md +164 -0
  47. package/skills/app-shell-patterns/references/components/card.md +109 -0
  48. package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
  49. package/skills/app-shell-patterns/references/components/combobox.md +318 -0
  50. package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
  51. package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
  52. package/skills/app-shell-patterns/references/components/data-table.md +953 -0
  53. package/skills/app-shell-patterns/references/components/date-picker.md +248 -0
  54. package/skills/app-shell-patterns/references/components/default-header.md +75 -0
  55. package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
  56. package/skills/app-shell-patterns/references/components/description-card.md +569 -0
  57. package/skills/app-shell-patterns/references/components/dialog.md +164 -0
  58. package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
  59. package/skills/app-shell-patterns/references/components/form.md +378 -0
  60. package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
  61. package/skills/app-shell-patterns/references/components/grid.md +184 -0
  62. package/skills/app-shell-patterns/references/components/input.md +83 -0
  63. package/skills/app-shell-patterns/references/components/layout.md +539 -0
  64. package/skills/app-shell-patterns/references/components/menu.md +218 -0
  65. package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
  66. package/skills/app-shell-patterns/references/components/select.md +283 -0
  67. package/skills/app-shell-patterns/references/components/sheet.md +237 -0
  68. package/skills/app-shell-patterns/references/components/sidebar-group.md +466 -0
  69. package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
  70. package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
  71. package/skills/app-shell-patterns/references/components/spinner.md +81 -0
  72. package/skills/app-shell-patterns/references/components/table.md +188 -0
  73. package/skills/app-shell-patterns/references/components/tabs.md +158 -0
  74. package/skills/app-shell-patterns/references/components/textarea.md +122 -0
  75. package/skills/app-shell-patterns/references/components/timeline.md +317 -0
  76. package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
  77. package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
  78. package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
  79. package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
  80. package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
  81. package/skills/app-shell-patterns/references/concepts/file-based-routing.md +350 -0
  82. package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +11 -4
  83. package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
  84. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +387 -0
  85. package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +388 -0
  86. package/skills/app-shell-patterns/references/{fundamental/design-system.md → concepts/styling-theming.md} +258 -110
  87. package/skills/app-shell-patterns/references/migrations.md +34 -0
  88. package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +4 -27
  89. package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
  90. package/skills/app-shell-patterns/references/patterns/form-modal.md +39 -100
  91. package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
  92. package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
  93. package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
  94. package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
  95. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +13 -27
  96. package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
  97. package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +11 -86
  98. package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
@@ -0,0 +1,258 @@
1
+ ---
2
+ title: SidebarLayout
3
+ description: Default AppShell layout with a built-in sidebar, content header, optional app-wide top bar, and an escape-hatch body slot
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/sidebar-layout.docs.outline.md — do not edit by hand. -->
7
+
8
+ # SidebarLayout
9
+
10
+ `SidebarLayout` is the default AppShell layout. By default it renders:
11
+
12
+ - `SidebarLayout.DefaultSidebar`
13
+ - `SidebarLayout.DefaultHeader`
14
+ - the current route outlet
15
+
16
+ You can replace the sidebar, replace the content header, add a full-width `topBar` above the whole shell, or take over the entire region beside the sidebar with the `body` slot.
17
+
18
+ If you want the opinionated "global app header + icon rail" mode, use [`GlobalHeaderLayout`](./global-header-layout.md), which is built on top of `SidebarLayout`.
19
+
20
+ ## Import
21
+
22
+ ```tsx
23
+ import { SidebarLayout } from "@tailor-platform/app-shell";
24
+ ```
25
+
26
+ ## Basic usage
27
+
28
+ ```tsx
29
+ import { AppShell, SidebarLayout } from "@tailor-platform/app-shell";
30
+
31
+ function App() {
32
+ return (
33
+ <AppShell modules={modules}>
34
+ <SidebarLayout />
35
+ </AppShell>
36
+ );
37
+ }
38
+ ```
39
+
40
+ This gives you:
41
+
42
+ - ✅ Responsive sidebar with auto-generated navigation from modules
43
+ - ✅ Breadcrumb navigation
44
+ - ✅ Theme toggle via the built-in header
45
+ - ✅ Mobile-friendly collapse behavior
46
+
47
+ ## Props
48
+
49
+ ### Common props
50
+
51
+ | Prop | Type | Default | Description |
52
+ | ------------- | ----------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------ |
53
+ | `sidebar` | `React.ReactNode` | `<SidebarLayout.DefaultSidebar />` | Replaces the entire sidebar region. |
54
+ | `defaultOpen` | `boolean` | `true` | Whether the sidebar starts expanded on desktop. |
55
+ | `collapsible` | `boolean` | `true` | Whether the sidebar can be collapsed. When `false`, toggle controls are hidden and `defaultOpen` is ignored. |
56
+ | `topBar` | `React.ReactNode` | - | Full-width bar above both the sidebar and the content region. |
57
+
58
+ ### Default content mode
59
+
60
+ Use this when AppShell should keep owning the content column.
61
+
62
+ | Prop | Type | Default | Description |
63
+ | ---------- | --------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------- |
64
+ | `header` | `React.ReactNode` | `<SidebarLayout.DefaultHeader />` | Replaces the content header above the main column. |
65
+ | `children` | `(props: { Outlet: () => React.ReactNode }) => React.ReactNode` | current route outlet | Custom content renderer that wraps or surrounds the outlet. |
66
+
67
+ ### Body-slot mode
68
+
69
+ Use this when you need to compose your own columns beside the sidebar.
70
+
71
+ | Prop | Type | Default | Description |
72
+ | ------ | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
73
+ | `body` | `React.ReactNode` | required | Replaces everything to the right of the sidebar. Compose it with `ContentContainer`, `Outlet`, and `Trigger`. |
74
+
75
+ `body` is mutually exclusive with `header` and `children`, because it replaces the region those props normally describe.
76
+
77
+ ## Extending the built-in header
78
+
79
+ The supported "small customization" path is to pass `SidebarLayout.DefaultHeader` into the `header` slot and fill its `actions` cluster.
80
+
81
+ ```tsx
82
+ import { AppearanceSwitcher, Button, SidebarLayout } from "@tailor-platform/app-shell";
83
+ import { BellIcon } from "lucide-react";
84
+
85
+ <SidebarLayout
86
+ header={
87
+ <SidebarLayout.DefaultHeader
88
+ actions={[
89
+ <Button key="notifications" variant="outline" size="icon" aria-label="Notifications">
90
+ <BellIcon className="size-4" />
91
+ </Button>,
92
+ <AppearanceSwitcher key="appearance" />,
93
+ ]}
94
+ />
95
+ }
96
+ />;
97
+ ```
98
+
99
+ `actions` replaces the entire right-hand cluster. If you still want the built-in appearance switcher, include `<AppearanceSwitcher />` yourself.
100
+
101
+ ## Replacing the sidebar
102
+
103
+ Pass `sidebar` to replace the whole left-side region. The built-in component is [`SidebarLayout.DefaultSidebar`](./default-sidebar.md), also exported as `DefaultSidebar`.
104
+
105
+ ```tsx
106
+ import {
107
+ SidebarGroup,
108
+ SidebarItem,
109
+ SidebarLayout,
110
+ SidebarSeparator,
111
+ } from "@tailor-platform/app-shell";
112
+
113
+ <SidebarLayout
114
+ sidebar={
115
+ <SidebarLayout.DefaultSidebar>
116
+ <SidebarItem to="/" />
117
+ <SidebarSeparator />
118
+ <SidebarGroup title="Main">
119
+ <SidebarItem to="/dashboard" />
120
+ <SidebarItem to="/orders" />
121
+ </SidebarGroup>
122
+ </SidebarLayout.DefaultSidebar>
123
+ }
124
+ />;
125
+ ```
126
+
127
+ ## Adding an app-wide top bar
128
+
129
+ `topBar` renders above the whole shell, spanning both the sidebar and the content region.
130
+
131
+ ```tsx
132
+ <SidebarLayout topBar={<MyGlobalTopBar />} sidebar={<SidebarLayout.DefaultSidebar hideHeader />} />
133
+ ```
134
+
135
+ When `topBar` is present, the fixed sidebar is offset below it. The bar should be `3.5rem` tall (`h-14`) to match the built-in layout.
136
+
137
+ If you specifically want AppShell's opinionated global-header mode, use [`GlobalHeaderLayout`](./global-header-layout.md), which wires the top bar, icon rail, and matching default sidebar for you.
138
+
139
+ ## Owning the region beside the sidebar
140
+
141
+ Use `body` when the stock content column is too restrictive and you need your own side columns.
142
+
143
+ ```tsx
144
+ <SidebarLayout
145
+ body={
146
+ <>
147
+ <aside className="w-64 shrink-0 overflow-y-auto border-r">
148
+ <TableOfContents />
149
+ </aside>
150
+ <SidebarLayout.ContentContainer header={<SidebarLayout.DefaultHeader />}>
151
+ <SidebarLayout.Outlet />
152
+ </SidebarLayout.ContentContainer>
153
+ <aside className="w-96 shrink-0 overflow-y-auto border-l">
154
+ <AssistantPanel />
155
+ </aside>
156
+ </>
157
+ }
158
+ />
159
+ ```
160
+
161
+ `SidebarLayout.ContentContainer` is the stock main column: inset padding, pinned header slot, scroll region, and `useAppShellScrollContainer()` support. `SidebarLayout.Trigger` exposes the built-in sidebar toggle so custom headers do not need DOM workarounds.
162
+
163
+ ## Reading and controlling the sidebar
164
+
165
+ Use `useAppShellSidebar()` to read and control the sidebar state instead of observing internal DOM attributes or clicking the trigger through the DOM.
166
+
167
+ ```tsx
168
+ import { useAppShellSidebar } from "@tailor-platform/app-shell";
169
+
170
+ function CustomHeader() {
171
+ const { open, isMobile, toggle } = useAppShellSidebar();
172
+
173
+ return (
174
+ <div className="flex items-center justify-between border-b px-4 py-3">
175
+ <button type="button" onClick={toggle}>
176
+ {open ? "Hide navigation" : "Show navigation"}
177
+ </button>
178
+ <span>{isMobile ? "Mobile" : "Desktop"}</span>
179
+ </div>
180
+ );
181
+ }
182
+ ```
183
+
184
+ Outside `SidebarLayout`, the hook returns a safe fallback (`open: true`, `isMobile: false`, no-op setters) rather than throwing.
185
+
186
+ ## Reusing the built-in breadcrumb
187
+
188
+ `DynamicBreadcrumb` is exported when you want the same route-driven breadcrumb in a custom header or top bar:
189
+
190
+ ```tsx
191
+ import { DynamicBreadcrumb, SidebarLayout } from "@tailor-platform/app-shell";
192
+
193
+ <header className="flex items-center gap-3 border-b px-4 py-3">
194
+ <SidebarLayout.Trigger />
195
+ <DynamicBreadcrumb />
196
+ </header>;
197
+ ```
198
+
199
+ ## Accessing the content scroll container
200
+
201
+ The AppShell is viewport-bounded (`h-svh`), so the **document itself does not scroll** — the content area does. Code that previously relied on `window`/document scroll (reading `window.scrollY`, listening to `window`'s `scroll` event, `window.scrollTo(...)`, or an `IntersectionObserver` with the default viewport root) should target the content scroll container instead.
202
+
203
+ Use the `useAppShellScrollContainer()` hook to get a ref to that element from any page:
204
+
205
+ ```tsx
206
+ import { useAppShellScrollContainer } from "@tailor-platform/app-shell";
207
+ import { useEffect, useState } from "react";
208
+
209
+ function ReadingProgress() {
210
+ const scrollRef = useAppShellScrollContainer();
211
+ const [progress, setProgress] = useState(0);
212
+
213
+ useEffect(() => {
214
+ const el = scrollRef.current;
215
+ if (!el) return;
216
+ const onScroll = () => {
217
+ const max = el.scrollHeight - el.clientHeight;
218
+ setProgress(max > 0 ? el.scrollTop / max : 0);
219
+ };
220
+ onScroll();
221
+ el.addEventListener("scroll", onScroll, { passive: true });
222
+ return () => el.removeEventListener("scroll", onScroll);
223
+ }, [scrollRef]);
224
+
225
+ return <progress value={progress} />;
226
+ }
227
+ ```
228
+
229
+ The same element handles imperative scrolling (`scrollRef.current?.scrollTo({ top: 0, behavior: "smooth" })`) and works as an `IntersectionObserver` root (`new IntersectionObserver(cb, { root: scrollRef.current })`).
230
+
231
+ Notes:
232
+
233
+ - The element mounts with the layout, above your page, so read `ref.current` inside an effect — it is populated by the time effects run, not during render.
234
+ - On a [`<Layout fill>`](./layout.md#fill-mode) page this element does **not** scroll; its children (for example a `DataTable`) manage their own scrolling.
235
+ - Outside a `SidebarLayout` (a fully custom layout) the returned ref's `current` is always `null` — such layouts own their own scroll region.
236
+ - For non-React access (CSS, tests, plain DOM) the container also carries a `data-appshell-scroll-container` attribute: `document.querySelector("[data-appshell-scroll-container]")`.
237
+
238
+ ## Styling
239
+
240
+ The sidebar and layout are styled with the library's internal `astw:`-prefixed utilities. Write **plain** Tailwind utilities in your own markup — see [Styling AppShell components](../concepts/styling-theming.md#styling-appshell-components).
241
+
242
+ ## Accessibility
243
+
244
+ SidebarLayout includes built-in accessibility features:
245
+
246
+ - **Keyboard navigation** for sidebar interaction
247
+ - **ARIA labels** on built-in controls
248
+ - **Focus management** when the sidebar opens on mobile
249
+ - **Responsive behavior** that works with keyboard, mouse, and touch input
250
+
251
+ ## Related
252
+
253
+ - [AppShell](./app-shell.md) - root component
254
+ - [DefaultHeader](./default-header.md) - built-in content header (`SidebarLayout.DefaultHeader`)
255
+ - [DefaultSidebar](./default-sidebar.md) - built-in sidebar (`SidebarLayout.DefaultSidebar`)
256
+ - [GlobalHeaderLayout](./global-header-layout.md) - opinionated app-wide header mode built on SidebarLayout
257
+ - [AppearanceSwitcher](./appearance-switcher.md) - color-theme dropdown for header actions
258
+ - [usePageMeta](../api/use-page-meta.md) - route metadata lookup used by sidebar items
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Spinner
3
+ description: Lightweight loading indicator component with accessible defaults and preset sizes
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/spinner.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Spinner
9
+
10
+ `Spinner` is AppShell's reusable loading indicator. It renders a small rotating SVG and is used throughout the built-in UI for loading states such as `ActionPanel`, command palette search, and CSV import progress.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { Spinner } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic usage
19
+
20
+ <example-preview name="basic-usage"></example-preview>
21
+
22
+ ```tsx
23
+ function BasicUsage() {
24
+ return <Spinner aria-label="Loading" />;
25
+ }
26
+ ```
27
+
28
+ ## Props
29
+
30
+ `Spinner` accepts all standard `<svg>` props plus one AppShell prop:
31
+
32
+ | Prop | Type | Default | Description |
33
+ | ------ | ----------------------------------- | ----------- | -------------------------------------------------------------------------- |
34
+ | `size` | `"xs" \| "sm" \| "default" \| "lg"` | `"default"` | Preset square size. Ignored when `width` or `height` is passed explicitly. |
35
+
36
+ Preset sizes map to:
37
+
38
+ | `size` | Pixels |
39
+ | ----------- | ------ |
40
+ | `"xs"` | `12` |
41
+ | `"sm"` | `14` |
42
+ | `"default"` | `16` |
43
+ | `"lg"` | `20` |
44
+
45
+ ## Accessibility
46
+
47
+ `Spinner` defaults to decorative output unless you give it an accessible name:
48
+
49
+ - with `aria-label` or `aria-labelledby`, it renders with `role="status"`
50
+ - with `aria-hidden={true}`, it stays decorative
51
+ - with neither, it is treated as decorative and gets `aria-hidden="true"`
52
+
53
+ Use a label when the spinner is the primary visible loading affordance:
54
+
55
+ ```tsx
56
+ <Spinner size="sm" aria-label="Loading orders" />
57
+ ```
58
+
59
+ When the surrounding control already has its own accessible name, keep the spinner decorative:
60
+
61
+ ```tsx
62
+ <Button disabled>
63
+ <Spinner size="sm" aria-hidden />
64
+ Saving
65
+ </Button>
66
+ ```
67
+
68
+ ## Sizing and styling
69
+
70
+ Pass ordinary Tailwind utilities through `className` for color and layout, or override the dimensions directly with `width` / `height`.
71
+
72
+ ```tsx
73
+ <Spinner className="text-muted-foreground" />
74
+ <Spinner size="lg" className="text-primary" aria-label="Generating report" />
75
+ <Spinner width={24} height={24} aria-label="Loading" />
76
+ ```
77
+
78
+ ## Related
79
+
80
+ - [ActionPanel](./action-panel.md) - uses `Spinner` for per-row loading states
81
+ - [WithGuard](./with-guard.md) - common place to render a loading spinner while guards resolve
@@ -0,0 +1,188 @@
1
+ ---
2
+ title: Table
3
+ description: Semantic HTML table with pre-styled sub-components
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/table.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Table
9
+
10
+ The `Table` component provides a set of pre-styled, semantic HTML table sub-components. It wraps a standard `<table>` element in a horizontally scrollable container.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { Table } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ <example-preview name="basic-usage"></example-preview>
21
+
22
+ ```tsx
23
+ function BasicUsage() {
24
+ return (
25
+ <Table.Root>
26
+ <Table.Header>
27
+ <Table.Row>
28
+ <Table.Head>Name</Table.Head>
29
+ <Table.Head>Email</Table.Head>
30
+ <Table.Head>Role</Table.Head>
31
+ </Table.Row>
32
+ </Table.Header>
33
+ <Table.Body>
34
+ <Table.Row>
35
+ <Table.Cell>Alice</Table.Cell>
36
+ <Table.Cell>alice@example.com</Table.Cell>
37
+ <Table.Cell>Admin</Table.Cell>
38
+ </Table.Row>
39
+ </Table.Body>
40
+ </Table.Root>
41
+ );
42
+ }
43
+ ```
44
+
45
+ ## Sub-components
46
+
47
+ | Sub-component | HTML element | Description |
48
+ | --------------- | ------------ | -------------------------------------- |
49
+ | `Table.Root` | `<table>` | Root element with scrollable container |
50
+ | `Table.Header` | `<thead>` | Table header section |
51
+ | `Table.Body` | `<tbody>` | Table body section |
52
+ | `Table.Footer` | `<tfoot>` | Table footer section |
53
+ | `Table.Row` | `<tr>` | Table row (hover and selection styles) |
54
+ | `Table.Head` | `<th>` | Header cell |
55
+ | `Table.Cell` | `<td>` | Data cell |
56
+ | `Table.Caption` | `<caption>` | Table caption |
57
+
58
+ ## Props
59
+
60
+ ### Table.Root Props
61
+
62
+ | Prop | Type | Default | Description |
63
+ | -------------------- | --------------------------- | ------- | ----------------------------------------------------------------- |
64
+ | `className` | `string` | - | Additional CSS classes for the `<table>` element |
65
+ | `containerClassName` | `string` | - | Additional CSS classes for the outer scrollable `<div>` container |
66
+ | `containerRef` | `React.Ref<HTMLDivElement>` | - | Ref forwarded to the outer scrollable `<div>` container |
67
+
68
+ All other standard HTML `<table>` props are accepted.
69
+
70
+ All other sub-components (`Table.Header`, `Table.Body`, `Table.Footer`, `Table.Row`, `Table.Head`, `Table.Cell`, `Table.Caption`) accept `className` and their corresponding standard HTML element props.
71
+
72
+ `Table.Head` and `Table.Cell` also accept `align?: "left" | "center" | "right"` for semantic text alignment without relying on utility-class overrides.
73
+
74
+ ## Examples
75
+
76
+ ### With Footer
77
+
78
+ ```tsx
79
+ <Table.Root>
80
+ <Table.Header>
81
+ <Table.Row>
82
+ <Table.Head>Product</Table.Head>
83
+ <Table.Head>Qty</Table.Head>
84
+ <Table.Head>Price</Table.Head>
85
+ </Table.Row>
86
+ </Table.Header>
87
+ <Table.Body>
88
+ <Table.Row>
89
+ <Table.Cell>Widget A</Table.Cell>
90
+ <Table.Cell>10</Table.Cell>
91
+ <Table.Cell>$100.00</Table.Cell>
92
+ </Table.Row>
93
+ <Table.Row>
94
+ <Table.Cell>Widget B</Table.Cell>
95
+ <Table.Cell>5</Table.Cell>
96
+ <Table.Cell>$75.00</Table.Cell>
97
+ </Table.Row>
98
+ </Table.Body>
99
+ <Table.Footer>
100
+ <Table.Row>
101
+ <Table.Cell colSpan={2}>Total</Table.Cell>
102
+ <Table.Cell>$175.00</Table.Cell>
103
+ </Table.Row>
104
+ </Table.Footer>
105
+ </Table.Root>
106
+ ```
107
+
108
+ ### With Caption
109
+
110
+ ```tsx
111
+ <Table.Root>
112
+ <Table.Caption>Order line items</Table.Caption>
113
+ <Table.Header>
114
+ <Table.Row>
115
+ <Table.Head>Item</Table.Head>
116
+ <Table.Head>Status</Table.Head>
117
+ </Table.Row>
118
+ </Table.Header>
119
+ <Table.Body>
120
+ <Table.Row>
121
+ <Table.Cell>Item 1</Table.Cell>
122
+ <Table.Cell>Shipped</Table.Cell>
123
+ </Table.Row>
124
+ </Table.Body>
125
+ </Table.Root>
126
+ ```
127
+
128
+ ### Right-aligned numeric columns
129
+
130
+ ```tsx
131
+ <Table.Root>
132
+ <Table.Header>
133
+ <Table.Row>
134
+ <Table.Head>Item</Table.Head>
135
+ <Table.Head align="right">Amount</Table.Head>
136
+ </Table.Row>
137
+ </Table.Header>
138
+ <Table.Body>
139
+ <Table.Row>
140
+ <Table.Cell>Widget A</Table.Cell>
141
+ <Table.Cell align="right">123</Table.Cell>
142
+ </Table.Row>
143
+ </Table.Body>
144
+ </Table.Root>
145
+ ```
146
+
147
+ ### Center-aligned status column
148
+
149
+ ```tsx
150
+ <Table.Root>
151
+ <Table.Header>
152
+ <Table.Row>
153
+ <Table.Head>Item</Table.Head>
154
+ <Table.Head align="center">Status</Table.Head>
155
+ </Table.Row>
156
+ </Table.Header>
157
+ <Table.Body>
158
+ <Table.Row>
159
+ <Table.Cell>Widget A</Table.Cell>
160
+ <Table.Cell align="center">Active</Table.Cell>
161
+ </Table.Row>
162
+ </Table.Body>
163
+ </Table.Root>
164
+ ```
165
+
166
+ ### Constrained Height with Scroll
167
+
168
+ ```tsx
169
+ <Table.Root containerClassName="max-h-64 overflow-y-auto">
170
+ <Table.Header>
171
+ <Table.Row>
172
+ <Table.Head>Name</Table.Head>
173
+ </Table.Row>
174
+ </Table.Header>
175
+ <Table.Body>
176
+ {items.map((item) => (
177
+ <Table.Row key={item.id}>
178
+ <Table.Cell>{item.name}</Table.Cell>
179
+ </Table.Row>
180
+ ))}
181
+ </Table.Body>
182
+ </Table.Root>
183
+ ```
184
+
185
+ ## Related Components
186
+
187
+ - [Badge](./badge.md) - Display status inside table cells
188
+ - [Layout](./layout.md) - Place tables inside page layouts
@@ -0,0 +1,158 @@
1
+ ---
2
+ title: Tabs
3
+ description: Tab navigation with a compound component API
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/tabs.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Tabs
9
+
10
+ The `Tabs` component provides tab-based navigation for toggling between related panels on the same page. It is backed by Base UI's Tabs primitive.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { Tabs } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ <example-preview name="basic-usage"></example-preview>
21
+
22
+ ```tsx
23
+ function BasicUsage() {
24
+ return (
25
+ <Tabs.Root defaultValue="overview">
26
+ <Tabs.List>
27
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
28
+ <Tabs.Tab value="projects">Projects</Tabs.Tab>
29
+ <Tabs.Tab value="account">Account</Tabs.Tab>
30
+ </Tabs.List>
31
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
32
+ <Tabs.Panel value="projects">Projects content</Tabs.Panel>
33
+ <Tabs.Panel value="account">Account content</Tabs.Panel>
34
+ </Tabs.Root>
35
+ );
36
+ }
37
+ ```
38
+
39
+ ## Sub-components
40
+
41
+ | Sub-component | Description |
42
+ | ------------- | -------------------------------------------------------------- |
43
+ | `Tabs.Root` | Manages tab selection state |
44
+ | `Tabs.List` | Groups the individual tab buttons |
45
+ | `Tabs.Tab` | An interactive tab button that toggles the corresponding panel |
46
+ | `Tabs.Panel` | A panel displayed when the corresponding tab is active |
47
+
48
+ ## Props
49
+
50
+ ### Tabs.Root Props
51
+
52
+ | Prop | Type | Default | Description |
53
+ | --------------- | ----------------------------------- | ----------- | ------------------------------------------------------------- |
54
+ | `defaultValue` | `Tabs.Tab.Value` | `0` | Initial active tab value (uncontrolled) |
55
+ | `value` | `Tabs.Tab.Value` | - | Controlled active tab value |
56
+ | `onValueChange` | `(value: any) => void` | - | Callback when the active tab changes |
57
+ | `variant` | `'default' \| 'line' \| 'capsule'` | `'default'` | Visual style of the tabs |
58
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'default'` | Minimum size (`capsule` only) — mirrors Button's height tiers |
59
+ | `className` | `string` | - | Additional CSS classes for root |
60
+ | `children` | `React.ReactNode` | - | Tabs sub-components |
61
+
62
+ ### Tabs.List Props
63
+
64
+ Accepts `className` and all standard HTML `<div>` props.
65
+
66
+ ### Tabs.Tab Props
67
+
68
+ | Prop | Type | Default | Description |
69
+ | ---------- | ---------------- | ------- | ---------------------------------- |
70
+ | `value` | `Tabs.Tab.Value` | - | **Required.** The value of the tab |
71
+ | `disabled` | `boolean` | - | Whether the tab is disabled |
72
+
73
+ Also accepts `className` and all standard HTML `<button>` props.
74
+
75
+ ### Tabs.Panel Props
76
+
77
+ | Prop | Type | Default | Description |
78
+ | ------------- | ---------------- | ------- | ------------------------------------------------------ |
79
+ | `value` | `Tabs.Tab.Value` | - | **Required.** The value matching the corresponding tab |
80
+ | `keepMounted` | `boolean` | `false` | Whether to keep the panel in the DOM when hidden |
81
+
82
+ Also accepts `className` and all standard HTML `<div>` props.
83
+
84
+ ## Controlled Usage
85
+
86
+ ```tsx
87
+ const [activeTab, setActiveTab] = useState("overview");
88
+
89
+ <Tabs.Root value={activeTab} onValueChange={setActiveTab}>
90
+ <Tabs.List>
91
+ <Tabs.Tab value="overview">Overview</Tabs.Tab>
92
+ <Tabs.Tab value="details">Details</Tabs.Tab>
93
+ </Tabs.List>
94
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
95
+ <Tabs.Panel value="details">Details content</Tabs.Panel>
96
+ </Tabs.Root>;
97
+ ```
98
+
99
+ ## Examples
100
+
101
+ ### With Disabled Tab
102
+
103
+ ```tsx
104
+ <Tabs.Root defaultValue="active">
105
+ <Tabs.List>
106
+ <Tabs.Tab value="active">Active</Tabs.Tab>
107
+ <Tabs.Tab value="pending">Pending</Tabs.Tab>
108
+ <Tabs.Tab value="archived" disabled>
109
+ Archived
110
+ </Tabs.Tab>
111
+ </Tabs.List>
112
+ <Tabs.Panel value="active">Active items</Tabs.Panel>
113
+ <Tabs.Panel value="pending">Pending items</Tabs.Panel>
114
+ <Tabs.Panel value="archived">Archived items</Tabs.Panel>
115
+ </Tabs.Root>
116
+ ```
117
+
118
+ ### Use Icons in Tab
119
+
120
+ In the `capsule` variant, a tab whose only child is an icon renders **square** —
121
+ its `min-width` matches its `min-height` — making it a natural fit for icon-only
122
+ view toggles (e.g. table/kanban). Use `size` to align the track with a sibling
123
+ `Button`: `size="default"` (36px) matches `Button`'s default height. Unsized
124
+ icons default to `16px`, so the square is consistent regardless of the icon.
125
+
126
+ > **Accessibility:** an icon-only tab has no visible text, so give each one an
127
+ > `aria-label`. Without it, screen readers announce an unnamed tab.
128
+
129
+ ```tsx
130
+ <Tabs.Root defaultValue="overview" variant="capsule" size="default">
131
+ <Tabs.List>
132
+ <Tabs.Tab value="overview" aria-label="Overview">
133
+ <LayoutDashboardIcon />
134
+ </Tabs.Tab>
135
+ <Tabs.Tab value="projects" aria-label="Projects">
136
+ <FolderKanbanIcon />
137
+ </Tabs.Tab>
138
+ <Tabs.Tab value="settings" aria-label="Settings">
139
+ <SettingsIcon />
140
+ </Tabs.Tab>
141
+ </Tabs.List>
142
+ <Tabs.Panel value="overview">Overview content</Tabs.Panel>
143
+ <Tabs.Panel value="projects">Projects content</Tabs.Panel>
144
+ <Tabs.Panel value="settings">Settings content</Tabs.Panel>
145
+ </Tabs.Root>
146
+ ```
147
+
148
+ ### Sizing the capsule variant
149
+
150
+ `size` mirrors `Button`'s height tiers, so a capsule can sit flush next to a
151
+ button. The value sets a **minimum** height — taller content still grows.
152
+
153
+ | `size` | Track height | Matches Button |
154
+ | --------- | ------------ | -------------- |
155
+ | `xs` | 28px | `size="xs"` |
156
+ | `sm` | 32px | `size="sm"` |
157
+ | `default` | 36px | default |
158
+ | `lg` | 40px | `size="lg"` |