@acronis-platform/ui-react 3.0.0 → 4.0.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 (219) hide show
  1. package/dist/components/ui/accordion-container/accordion-container.js +14 -14
  2. package/dist/components/ui/accordion-container/accordion-container.js.map +1 -1
  3. package/dist/components/ui/app-shell-chat/app-shell-chat.js.map +1 -1
  4. package/dist/components/ui/area-chart/area-chart.js +141 -139
  5. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  6. package/dist/components/ui/bar-chart/bar-chart.js +295 -293
  7. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  8. package/dist/components/ui/category-bar/category-bar.js +109 -93
  9. package/dist/components/ui/category-bar/category-bar.js.map +1 -1
  10. package/dist/components/ui/chart/chart-palette.js +113 -0
  11. package/dist/components/ui/chart/chart-palette.js.map +1 -0
  12. package/dist/components/ui/chart/chart.js +176 -129
  13. package/dist/components/ui/chart/chart.js.map +1 -1
  14. package/dist/components/ui/chart-state/chart-state-illustrations.js +310 -0
  15. package/dist/components/ui/chart-state/chart-state-illustrations.js.map +1 -0
  16. package/dist/components/ui/chart-state/chart-state.js +48 -34
  17. package/dist/components/ui/chart-state/chart-state.js.map +1 -1
  18. package/dist/components/ui/chart-widget/chart-widget.js +87 -0
  19. package/dist/components/ui/chart-widget/chart-widget.js.map +1 -0
  20. package/dist/components/ui/composed-chart/composed-chart.js +117 -115
  21. package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
  22. package/dist/components/ui/confidence-cone/confidence-cone.js +166 -158
  23. package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
  24. package/dist/components/ui/funnel-chart/funnel-chart.js +162 -161
  25. package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
  26. package/dist/components/ui/histogram/histogram.js +94 -92
  27. package/dist/components/ui/histogram/histogram.js.map +1 -1
  28. package/dist/components/ui/input/input.js.map +1 -1
  29. package/dist/components/ui/label/label.js +2 -9
  30. package/dist/components/ui/label/label.js.map +1 -1
  31. package/dist/components/ui/line-chart/line-chart.js +143 -141
  32. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  33. package/dist/components/ui/metric/metric.js +74 -185
  34. package/dist/components/ui/metric/metric.js.map +1 -1
  35. package/dist/components/ui/page-content/page-content.js.map +1 -1
  36. package/dist/components/ui/pie-chart/pie-chart.js +201 -195
  37. package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
  38. package/dist/components/ui/radar-chart/radar-chart.js +133 -131
  39. package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
  40. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +297 -265
  41. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
  42. package/dist/components/ui/sankey-chart/sankey-chart.js +123 -101
  43. package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
  44. package/dist/components/ui/scatter-chart/scatter-chart.js +76 -74
  45. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  46. package/dist/components/ui/section/section.js +157 -31
  47. package/dist/components/ui/section/section.js.map +1 -1
  48. package/dist/components/ui/stepper/stepper.js +24 -24
  49. package/dist/components/ui/stepper/stepper.js.map +1 -1
  50. package/dist/components/ui/stepper-item/stepper-item.js +43 -24
  51. package/dist/components/ui/stepper-item/stepper-item.js.map +1 -1
  52. package/dist/components/ui/treemap/treemap.js +133 -124
  53. package/dist/components/ui/treemap/treemap.js.map +1 -1
  54. package/dist/components/ui/trend-indicator/trend-indicator.js +34 -69
  55. package/dist/components/ui/trend-indicator/trend-indicator.js.map +1 -1
  56. package/dist/components/ui/wizard/wizard.js +59 -0
  57. package/dist/components/ui/wizard/wizard.js.map +1 -0
  58. package/dist/hooks/use-wizard.js +75 -0
  59. package/dist/hooks/use-wizard.js.map +1 -0
  60. package/dist/index.js +502 -497
  61. package/dist/index.js.map +1 -1
  62. package/dist/llms/accordion-container.md +181 -0
  63. package/dist/llms/accordion.md +124 -0
  64. package/dist/llms/alert.md +225 -0
  65. package/dist/llms/app-shell-chat.md +415 -0
  66. package/dist/llms/area-chart.md +355 -0
  67. package/dist/llms/avatar.md +208 -0
  68. package/dist/llms/bar-chart.md +406 -0
  69. package/dist/llms/breadcrumb.md +326 -0
  70. package/dist/llms/button-group.md +298 -0
  71. package/dist/llms/button-icon-input.md +142 -0
  72. package/dist/llms/button-icon-menu.md +209 -0
  73. package/dist/llms/button-icon.md +128 -0
  74. package/dist/llms/button-menu.md +172 -0
  75. package/dist/llms/button.md +185 -0
  76. package/dist/llms/calendar-panel.md +733 -0
  77. package/dist/llms/calendar.md +188 -0
  78. package/dist/llms/card-filter.md +214 -0
  79. package/dist/llms/card-section.md +293 -0
  80. package/dist/llms/card.md +447 -0
  81. package/dist/llms/carousel-dialog.md +156 -0
  82. package/dist/llms/category-bar.md +193 -0
  83. package/dist/llms/chart-state.md +190 -0
  84. package/dist/llms/chart-widget.md +209 -0
  85. package/dist/llms/chart.md +182 -0
  86. package/dist/llms/checkbox.md +257 -0
  87. package/dist/llms/chip.md +195 -0
  88. package/dist/llms/combobox.md +164 -0
  89. package/dist/llms/composed-chart.md +508 -0
  90. package/dist/llms/confidence-cone.md +277 -0
  91. package/dist/llms/data-table.md +474 -0
  92. package/dist/llms/date-range-picker.md +272 -0
  93. package/dist/llms/description-list.md +131 -0
  94. package/dist/llms/dialog-footer-carousel.md +147 -0
  95. package/dist/llms/dialog-footer-default.md +142 -0
  96. package/dist/llms/dialog-root.md +246 -0
  97. package/dist/llms/dialog-welcome.md +223 -0
  98. package/dist/llms/dialog.md +403 -0
  99. package/dist/llms/dropdown-menu.md +193 -0
  100. package/dist/llms/empty-overlay.md +146 -0
  101. package/dist/llms/empty.md +156 -0
  102. package/dist/llms/field.md +185 -0
  103. package/dist/llms/filter-cards.md +157 -0
  104. package/dist/llms/filter-chips.md +323 -0
  105. package/dist/llms/filter-search.md +512 -0
  106. package/dist/llms/form.md +154 -0
  107. package/dist/llms/funnel-chart.md +333 -0
  108. package/dist/llms/grid.md +80 -0
  109. package/dist/llms/histogram.md +190 -0
  110. package/dist/llms/input-date-picker.md +203 -0
  111. package/dist/llms/input-otp.md +173 -0
  112. package/dist/llms/input-password.md +197 -0
  113. package/dist/llms/input-search.md +170 -0
  114. package/dist/llms/input-select.md +278 -0
  115. package/dist/llms/input-text-area.md +271 -0
  116. package/dist/llms/input-text.md +192 -0
  117. package/dist/llms/line-chart.md +369 -0
  118. package/dist/llms/link.md +209 -0
  119. package/dist/llms/loading.md +130 -0
  120. package/dist/llms/meter.md +177 -0
  121. package/dist/llms/metric.md +204 -0
  122. package/dist/llms/number-field.md +122 -0
  123. package/dist/llms/page-content.md +69 -0
  124. package/dist/llms/page-header.md +182 -0
  125. package/dist/llms/pagination.md +133 -0
  126. package/dist/llms/pie-chart.md +307 -0
  127. package/dist/llms/popover.md +252 -0
  128. package/dist/llms/progress-circle.md +126 -0
  129. package/dist/llms/progress.md +111 -0
  130. package/dist/llms/radar-chart.md +316 -0
  131. package/dist/llms/radial-bar-chart.md +319 -0
  132. package/dist/llms/radio.md +255 -0
  133. package/dist/llms/resizable.md +195 -0
  134. package/dist/llms/sankey-chart.md +208 -0
  135. package/dist/llms/scatter-chart.md +239 -0
  136. package/dist/llms/scroll-area.md +183 -0
  137. package/dist/llms/section.md +401 -0
  138. package/dist/llms/select.md +210 -0
  139. package/dist/llms/separator.md +87 -0
  140. package/dist/llms/sheet.md +202 -0
  141. package/dist/llms/sidebar-primary.md +360 -0
  142. package/dist/llms/sidebar-secondary.md +417 -0
  143. package/dist/llms/skeleton.md +81 -0
  144. package/dist/llms/slider.md +97 -0
  145. package/dist/llms/spinner.md +100 -0
  146. package/dist/llms/stack.md +80 -0
  147. package/dist/llms/stepper-item.md +309 -0
  148. package/dist/llms/stepper.md +251 -0
  149. package/dist/llms/switch.md +140 -0
  150. package/dist/llms/table.md +436 -0
  151. package/dist/llms/tabs.md +197 -0
  152. package/dist/llms/tag.md +139 -0
  153. package/dist/llms/timeline.md +361 -0
  154. package/dist/llms/timer.md +259 -0
  155. package/dist/llms/toast.md +241 -0
  156. package/dist/llms/toggle-group.md +121 -0
  157. package/dist/llms/toolbar.md +453 -0
  158. package/dist/llms/tooltip.md +164 -0
  159. package/dist/llms/treemap.md +254 -0
  160. package/dist/llms/trend-indicator.md +132 -0
  161. package/dist/llms/widget-placeholder.md +169 -0
  162. package/dist/llms/wizard.md +412 -0
  163. package/dist/llms.txt +142 -0
  164. package/dist/react.js +502 -497
  165. package/dist/react.js.map +1 -1
  166. package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
  167. package/dist/src/components/ui/avatar/avatar.d.ts +1 -1
  168. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
  169. package/dist/src/components/ui/category-bar/category-bar.d.ts +10 -4
  170. package/dist/src/components/ui/chart/__stories__/palette-control.d.ts +48 -0
  171. package/dist/src/components/ui/chart/__tests__/chart-palette.test.d.ts +1 -0
  172. package/dist/src/components/ui/chart/chart-palette.d.ts +128 -0
  173. package/dist/src/components/ui/chart/chart.d.ts +66 -15
  174. package/dist/src/components/ui/chart/index.d.ts +4 -2
  175. package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +6 -0
  176. package/dist/src/components/ui/chart-state/chart-state.d.ts +13 -2
  177. package/dist/src/components/ui/chart-state/index.d.ts +1 -0
  178. package/dist/src/components/ui/chart-widget/chart-widget.d.ts +64 -0
  179. package/dist/src/components/ui/chart-widget/index.d.ts +1 -0
  180. package/dist/src/components/ui/composed-chart/composed-chart.d.ts +12 -7
  181. package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +10 -5
  182. package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +1 -1
  183. package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
  184. package/dist/src/components/ui/histogram/histogram.d.ts +10 -4
  185. package/dist/src/components/ui/label/index.d.ts +1 -1
  186. package/dist/src/components/ui/label/label.d.ts +1 -5
  187. package/dist/src/components/ui/line-chart/line-chart.d.ts +9 -4
  188. package/dist/src/components/ui/metric/metric.d.ts +13 -14
  189. package/dist/src/components/ui/pie-chart/pie-chart.d.ts +17 -8
  190. package/dist/src/components/ui/radar-chart/radar-chart.d.ts +10 -5
  191. package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +17 -6
  192. package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +10 -5
  193. package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +10 -5
  194. package/dist/src/components/ui/section/index.d.ts +1 -1
  195. package/dist/src/components/ui/section/section.d.ts +75 -6
  196. package/dist/src/components/ui/stepper-item/stepper-item.d.ts +6 -5
  197. package/dist/src/components/ui/tag/tag.d.ts +1 -1
  198. package/dist/src/components/ui/treemap/treemap.d.ts +11 -5
  199. package/dist/src/components/ui/trend-indicator/trend-indicator.d.ts +3 -7
  200. package/dist/src/components/ui/wizard/index.d.ts +1 -0
  201. package/dist/src/components/ui/wizard/wizard.d.ts +6 -0
  202. package/dist/src/hooks/index.d.ts +1 -0
  203. package/dist/src/hooks/use-wizard.d.ts +80 -0
  204. package/dist/src/index.d.ts +2 -3
  205. package/dist/ui-react.css +1 -1
  206. package/package.json +9 -3
  207. package/dist/components/ui/app-shell/app-shell.js +0 -75
  208. package/dist/components/ui/app-shell/app-shell.js.map +0 -1
  209. package/dist/components/ui/auth-layout/auth-layout.js +0 -56
  210. package/dist/components/ui/auth-layout/auth-layout.js.map +0 -1
  211. package/dist/components/ui/collapsible/collapsible.js +0 -22
  212. package/dist/components/ui/collapsible/collapsible.js.map +0 -1
  213. package/dist/src/components/ui/app-shell/app-shell.d.ts +0 -8
  214. package/dist/src/components/ui/app-shell/index.d.ts +0 -1
  215. package/dist/src/components/ui/auth-layout/auth-layout.d.ts +0 -6
  216. package/dist/src/components/ui/auth-layout/index.d.ts +0 -1
  217. package/dist/src/components/ui/collapsible/collapsible.d.ts +0 -5
  218. package/dist/src/components/ui/collapsible/index.d.ts +0 -1
  219. package/dist/src/components/ui/label/label.docs.d.ts +0 -10
@@ -0,0 +1,183 @@
1
+ # ScrollArea
2
+
3
+ > A scrollable region with a custom overlay scrollbar built on the Base UI Scroll Area primitive. The bar floats over the content and reserves no layout space, so full-bleed content is never cropped by a scrollbar gutter, on every OS and browser. The bar is revealed on hover/scroll and hidden at rest. Ported from the legacy shadcn-uikit `ScrollArea`.
4
+
5
+ **Status:** draft · **Category:** layout · **Since:** v0.53.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { ScrollArea, ScrollBar } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ <ScrollArea className="h-72">
17
+ {longContent}
18
+ </ScrollArea>
19
+ <ScrollArea orientation="both" className="h-72 w-96">
20
+ {wideTallContent}
21
+ </ScrollArea>
22
+ ```
23
+
24
+ A scrollable region with a custom **overlay** scrollbar built on the Base UI
25
+ Scroll Area primitive. The bar floats over the content and reserves **no**
26
+ layout space, so full-bleed content is never cropped by a scrollbar gutter — on
27
+ every OS and browser, not just where the platform happens to provide overlay
28
+ scrollbars. It is hidden at rest and revealed on hover/scroll.
29
+
30
+ > Design-pending v1: ported from the legacy shadcn-uikit `ScrollArea`. No Figma
31
+ > node yet; reconcile with `/figma-component ScrollArea <url> --update` once a
32
+ > design lands.
33
+
34
+ ## When to use
35
+
36
+ - A fixed-height (or fixed-width) region whose content can overflow — sidebars,
37
+ menus, popovers, lists, code blocks, image strips.
38
+ - Anywhere a native `overflow: auto` scrollbar's **reserved gutter** would crop
39
+ edge-to-edge content (e.g. a sidebar's full-width selected row) or shift the
40
+ layout when the scrollbar appears.
41
+
42
+ ## When not to use
43
+
44
+ - Page-level / document scrolling — let the browser own that.
45
+ - Very large/virtualized data sets — pair a virtualizer with the viewport, or
46
+ use a component designed for virtualization.
47
+
48
+ ## Examples
49
+
50
+ ```tsx
51
+ import { ScrollArea } from '@acronis-platform/ui-react';
52
+
53
+ <ScrollArea className="h-72 w-64 rounded-md border border-border">
54
+ {longList}
55
+ </ScrollArea>;
56
+ ```
57
+
58
+ ```tsx
59
+ // Both axes (renders the corner too)
60
+ <ScrollArea orientation="both" className="h-72 w-96">
61
+ {wideTallContent}
62
+ </ScrollArea>
63
+ ```
64
+
65
+ ```tsx
66
+ // Compose the parts directly for custom scrollbar placement
67
+ import { ScrollArea, ScrollBar } from '@acronis-platform/ui-react';
68
+
69
+ <ScrollArea orientation="horizontal">
70
+ {row}
71
+ <ScrollBar orientation="horizontal" />
72
+ </ScrollArea>;
73
+ ```
74
+
75
+ ## Parts
76
+
77
+ | Part | Element | Notes |
78
+ | ------------ | ------- | ------------------------------------------------------------- |
79
+ | `ScrollArea` | `div` | Root + viewport + content + built-in scrollbar(s) (+ corner). |
80
+ | `ScrollBar` | `div` | Standalone overlay scrollbar (track + thumb); `orientation`. |
81
+
82
+ ## Props
83
+
84
+ - `orientation` — `'vertical'` (default) · `'horizontal'` · `'both'`. Selects
85
+ the built-in scrollbar(s); `'both'` also renders the corner.
86
+ - All other props pass through to the Base UI `ScrollArea.Root`.
87
+
88
+ ## Props
89
+
90
+ | Prop | Type | Default | Required | Description |
91
+ |------|------|---------|----------|-------------|
92
+ | `orientation` | `'vertical' | 'horizontal' | 'both'` | `'vertical'` | no | Which scrollbar(s) the all-in-one `ScrollArea` renders. `both` also renders the corner. For finer control, compose the exported `ScrollBar` part directly. |
93
+
94
+ ## Content slots
95
+
96
+ | Slot | Description |
97
+ |------|-------------|
98
+ | `children` | The content to be scrolled, wrapped in the viewport/content parts. |
99
+
100
+ ## Behavior
101
+
102
+ Given/When/Then scenarios for the scroll area.
103
+
104
+ ### Overlay scrollbar — no reserved gutter
105
+
106
+ - **Given** content taller than the scroll area
107
+ **When** it renders
108
+ **Then** the content fills the full width of the viewport (the scrollbar
109
+ floats over it and reserves **no** layout space), so edge-to-edge content is
110
+ not cropped by a scrollbar gutter.
111
+
112
+ ### Reveal on hover / scroll
113
+
114
+ - **Given** a scrollable area at rest
115
+ **Then** the scrollbar is hidden (opacity 0).
116
+ - **When** the pointer hovers the area, or the viewport is scrolled
117
+ **Then** the scrollbar fades in (driven by the primitive's `data-hovering` /
118
+ `data-scrolling` state), and fades back out when the interaction ends.
119
+
120
+ ### Orientation
121
+
122
+ - **Given** `orientation="vertical"` (default)
123
+ **Then** only a vertical scrollbar is rendered.
124
+ - **Given** `orientation="horizontal"`
125
+ **Then** only a horizontal scrollbar is rendered.
126
+ - **Given** `orientation="both"`
127
+ **Then** both scrollbars are rendered plus the corner that fills the gap where
128
+ they meet.
129
+
130
+ ### Dragging the thumb
131
+
132
+ - **When** the user presses and drags the thumb
133
+ **Then** the viewport scrolls proportionally; the thumb darkens
134
+ (`--ui-border-on-surface-border-active`) on hover.
135
+
136
+ ### Keyboard
137
+
138
+ - **Given** the viewport is focused
139
+ **When** the user presses arrow keys / Page Up / Page Down / Home / End
140
+ **Then** the viewport scrolls accordingly (native scrolling on the focusable
141
+ viewport).
142
+
143
+ ## Accessibility
144
+
145
+ ## Roles & semantics
146
+
147
+ - The parts are plain `<div>`s; the component adds no landmark role. The
148
+ scrollable **viewport** is focusable so the region is reachable and operable
149
+ by keyboard.
150
+ - Content semantics are entirely the caller's — `ScrollArea` is a transparent
151
+ scroll container around arbitrary children.
152
+
153
+ ## Keyboard
154
+
155
+ | Key | Action |
156
+ | ---------------------------- | -------------------------- |
157
+ | `Tab` | Move focus to the viewport |
158
+ | `Arrow Up` / `Arrow Down` | Scroll vertically |
159
+ | `Arrow Left` / `Arrow Right` | Scroll horizontally |
160
+ | `Page Up` / `Page Down` | Scroll by a page |
161
+ | `Home` / `End` | Scroll to start / end |
162
+
163
+ ## Focus
164
+
165
+ - The viewport shows a visible focus ring (`--ui-focus-brand`) on
166
+ `:focus-visible`, so keyboard users can see when the scroll region holds focus.
167
+
168
+ ## Screen readers
169
+
170
+ - No content is hidden from assistive tech: the scrollbar and corner are
171
+ decorative overlays; the scrolled children remain in the normal reading order.
172
+
173
+ ## Pointer / motion
174
+
175
+ - The scrollbar reveal is an opacity transition only (no layout shift, no
176
+ parallax). The thumb remains operable by mouse drag and by the native
177
+ scroll gestures (wheel, trackpad, touch).
178
+
179
+ ## Contrast
180
+
181
+ - The thumb uses the shared border token at rest and a darker active token on
182
+ hover, both of which meet non-text contrast against the page surfaces in the
183
+ shipped themes.
@@ -0,0 +1,401 @@
1
+ # Section
2
+
3
+ > A titled band that groups cards — or a table — on a page. Four content layouts pick the body shape: one full-width column, a 70/30 split, a three-column card grid, or a flush table that bleeds to the page edges. The header carries a title, optional description, an optional toggle switch, inline extras, and end-aligned actions; an optional bottom divider separates one band from the next. Collapsing is a composition with `AccordionContainer`, the same as `Card`.
4
+
5
+ **Status:** ready · **Category:** layout · **Since:** v3.0.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { Section, SectionHeader, SectionContent } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ <Section variant="grid3" hasBottomBorder>
17
+ <SectionHeader
18
+ title="Protection"
19
+ description="3 plans applied to 24 workloads."
20
+ hasDescription
21
+ />
22
+ <SectionContent>
23
+ <Card>…</Card>
24
+ <Card>…</Card>
25
+ <Card>…</Card>
26
+ </SectionContent>
27
+ </Section>
28
+
29
+ // A 70/30 split.
30
+ <Section variant="column2-70-30">
31
+ <SectionHeader title="Storage" />
32
+ <SectionContent secondaryContent={<Card>…</Card>}>
33
+ <Card>…</Card>
34
+ </SectionContent>
35
+ </Section>
36
+
37
+ // Collapsible — a composition, not a prop.
38
+ <Section>
39
+ <AccordionContainer collapsible defaultOpen>
40
+ <SectionHeader title="Protection" isCollapsible />
41
+ <AccordionContainer.Content>
42
+ <SectionContent>…</SectionContent>
43
+ </AccordionContainer.Content>
44
+ </AccordionContainer>
45
+ </Section>
46
+ ```
47
+
48
+ A titled band that groups content on a page. Where `Card` owns a single surface
49
+ and `CardSection` divides a card's body, `Section` is the layer above both: it
50
+ labels a run of cards — or a table — and separates it from the next run.
51
+
52
+ ## When to use
53
+
54
+ - A page that reads as **several labelled bands** ("General", "Protection",
55
+ "Danger zone"), each holding one or more cards.
56
+ - A **row of cards** that needs a shared title and a consistent three-column
57
+ grid (`grid3`).
58
+ - A **primary/secondary split** where a wide main area is paired with a narrow
59
+ companion column (`column2-70-30`).
60
+ - A **full-bleed table** with a page-level title above it (`table`).
61
+
62
+ ## When not to use
63
+
64
+ - Inside a card. Use `CardSection` — it is card chrome, with the smaller 14px
65
+ header and the card's own inset rhythm.
66
+ - As a bare layout wrapper with no title. Use `Stack` / `Grid`; a section with
67
+ no header adds a band with no meaning.
68
+ - As a surface. `Section` paints no background of its own; the page surface
69
+ shows through.
70
+
71
+ ## Parts
72
+
73
+ | Part | Element | Notes |
74
+ | ---------------- | --------- | --------------------------------------------------------------------------- |
75
+ | `Section` | `section` | Owns `variant` + `hasBottomBorder` and publishes the layout to its parts. |
76
+ | `SectionHeader` | `div` | Optional. Switch, title, description, extras, `children`, actions, trigger. |
77
+ | `SectionContent` | `div` | The body. Its layout comes from the root's `variant`. |
78
+
79
+ ## Layouts
80
+
81
+ | `variant` | Body |
82
+ | --------------- | ----------------------------------------------------------- |
83
+ | `column1` | One full-width area (default). |
84
+ | `column2-70-30` | 3-column grid; children span 2, `secondaryContent` spans 1. |
85
+ | `grid3` | 3-column grid the children flow into. |
86
+ | `table` | Flush — no root padding, so rows bleed to the page edges. |
87
+
88
+ ## Examples
89
+
90
+ A row of cards under one title:
91
+
92
+ ```tsx
93
+ <Section variant="grid3">
94
+ <SectionHeader title="Recent activity" />
95
+ <SectionContent>
96
+ <Card>…</Card>
97
+ <Card>…</Card>
98
+ <Card>…</Card>
99
+ </SectionContent>
100
+ </Section>
101
+ ```
102
+
103
+ A 70/30 split:
104
+
105
+ ```tsx
106
+ <Section variant="column2-70-30">
107
+ <SectionHeader
108
+ title="Storage"
109
+ description="Usage across every connected location."
110
+ hasDescription
111
+ />
112
+ <SectionContent secondaryContent={<QuotaCard />}>
113
+ <LocationsCard />
114
+ </SectionContent>
115
+ </Section>
116
+ ```
117
+
118
+ A full-bleed table:
119
+
120
+ ```tsx
121
+ <Section variant="table">
122
+ <SectionHeader
123
+ title="Workloads"
124
+ actions={
125
+ <ButtonIcon aria-label="More actions">
126
+ <EllipsisIcon size={24} />
127
+ </ButtonIcon>
128
+ }
129
+ />
130
+ <SectionContent>
131
+ <WorkloadsTable />
132
+ </SectionContent>
133
+ </Section>
134
+ ```
135
+
136
+ Collapsible — a composition with the shared disclosure primitive, not a prop:
137
+
138
+ ```tsx
139
+ <Section variant="grid3">
140
+ <AccordionContainer collapsible defaultOpen>
141
+ <SectionHeader
142
+ title="Protection"
143
+ isCollapsible
144
+ collapseLabel="Toggle protection section"
145
+ />
146
+ <AccordionContainer.Content>
147
+ <SectionContent>…</SectionContent>
148
+ </AccordionContainer.Content>
149
+ </AccordionContainer>
150
+ </Section>
151
+ ```
152
+
153
+ ## Notes
154
+
155
+ - **No bottom padding without `hasBottomBorder`.** Stacked unbordered sections
156
+ would otherwise double their vertical gap, since the next one already opens
157
+ with its own top inset. Set `hasBottomBorder` on every section but the last
158
+ when you want visible separators.
159
+ - **The `table` variant is flush on purpose.** It has no padding on any side so
160
+ its rows reach the page edges; only the header re-applies the horizontal
161
+ inset. `hasBottomBorder` adds the divider without reintroducing padding.
162
+ - **`variant` is set once, on the root.** The header and content parts read it
163
+ from context, so there is nothing to keep in sync.
164
+ - **Collapsing lives in `AccordionContainer`.** `isCollapsible` only renders the
165
+ trigger; the open/closed state, ARIA wiring, and height animation belong to
166
+ the container — the same split `Card` uses.
167
+ - **Override `collapseLabel` / `switchLabel`** whenever a page stacks several
168
+ collapsible or switchable sections; the defaults are generic by necessity.
169
+
170
+ ## Props
171
+
172
+ | Prop | Type | Default | Required | Description |
173
+ |------|------|---------|----------|-------------|
174
+ | `variant` | `'column1' | 'column2-70-30' | 'grid3' | 'table'` | `column1` | no | Root. Which content layout the section uses. `column1` is one full-width area; `column2-70-30` splits the body into a wide and a narrow column; `grid3` flows children into a three-column card grid; `table` drops the root inset entirely so a table's rows run edge-to-edge. The root publishes this to its header and content parts, so the consumer sets it in exactly one place. |
175
+ | `hasBottomBorder` | `boolean` | `false` | no | Root. Draws a bottom divider plus the matching bottom padding, separating this band from the next one stacked below it. Without it the root reserves no bottom padding at all, because the next section opens with its own top inset. The `table` variant stays flush either way and only gains the divider. |
176
+ | `title` | `string` | `undefined` | no | Header. The section title, at the 20px medium "headings/section" scale. Renders nothing when omitted. |
177
+ | `description` | `string` | `undefined` | no | Header. Supporting text under the title; shown only with `hasDescription`. |
178
+ | `hasDescription` | `boolean` | `false` | no | Header. Shows `description` below the title. |
179
+ | `isSwitchable` | `boolean` | `false` | no | Header. Shows a toggle switch at the start of the header, for turning the whole grouping on or off. |
180
+ | `switchChecked` | `boolean` | `undefined` | no | Header. Controlled checked state of the header switch. |
181
+ | `defaultSwitchChecked` | `boolean` | `undefined` | no | Header. Uncontrolled initial checked state of the header switch. |
182
+ | `switchDisabled` | `boolean` | `undefined` | no | Header. Disables the header switch. |
183
+ | `switchLabel` | `string` | `Toggle section` | no | Header. Accessible label for the header switch. |
184
+ | `extras` | `ReactNode` | `undefined` | no | Header. Content rendered inline next to the title (e.g. a tag). |
185
+ | `actions` | `ReactNode` | `undefined` | no | Header. Actions rendered at the end of the header row. |
186
+ | `isCollapsible` | `boolean` | `false` | no | Header. Renders the disclosure trigger at the end of the header. Only has an effect inside a collapsible `AccordionContainer`, which owns the open/closed state. |
187
+ | `collapseLabel` | `string` | `Collapse section` | no | Header. Accessible label for the collapse trigger. |
188
+ | `secondaryContent` | `ReactNode` | `undefined` | no | Content. The narrow (~30%) second column of the `column2-70-30` layout. Ignored by every other variant, which has a single content area. |
189
+ | `render` | `RenderProp` | `undefined` | no | Base UI composition prop — replaces the rendered element with another component while merging props and classes. Available on every part. React-only; other frameworks use their own polymorphism. |
190
+
191
+ ## Events
192
+
193
+ | Event | Payload | Description |
194
+ |-------|---------|-------------|
195
+ | `switch-checked-change` | `boolean` | Header. Fires when the header switch is toggled. |
196
+
197
+ ## Content slots
198
+
199
+ | Slot | Description |
200
+ |------|-------------|
201
+ | `default` | On the root, the section's parts (header, content). On the header, an additional slot rendered after the title/description block and before `actions` — used to supply a custom heading element (see accessibility.md). On the content part, the body itself — the wide column under `column2-70-30`, the grid items under `grid3`, and everything under `column1` / `table`. |
202
+
203
+ ## Behavior
204
+
205
+ ### Choosing a content layout
206
+
207
+ **Given** a `Section` with no `variant`
208
+ **When** it renders
209
+ **Then** it uses `column1`: the content part is one full-width area with no
210
+ imposed grid.
211
+
212
+ **Given** `variant="column2-70-30"`
213
+ **When** it renders
214
+ **Then** the content part is a three-column grid; the children span two columns
215
+ (~70%) and `secondaryContent` the remaining one (~30%). With no
216
+ `secondaryContent` the narrow column is not rendered at all and the wide column
217
+ keeps its 2:1 span rather than stretching.
218
+
219
+ **Given** `variant="grid3"`
220
+ **When** it renders
221
+ **Then** the content part is a three-column grid the children flow into. No row
222
+ count is imposed — four children wrap onto a second row.
223
+
224
+ **Given** `variant="table"`
225
+ **When** it renders
226
+ **Then** the root drops its padding entirely so the table's rows bleed to the
227
+ page edges, and the header re-applies the horizontal inset so the title still
228
+ lines up with the first column.
229
+
230
+ **Given** `secondaryContent` under any variant other than `column2-70-30`
231
+ **When** it renders
232
+ **Then** it is ignored — those layouts have a single content area.
233
+
234
+ ### Stacking sections down a page
235
+
236
+ **Given** a section with `hasBottomBorder` unset
237
+ **When** it renders
238
+ **Then** no divider is painted and **no bottom padding is reserved**. This is
239
+ deliberate: the next section down opens with its own top inset, so reserving
240
+ bottom padding here would double the gap between two unbordered bands.
241
+
242
+ **Given** several sections stacked on one page
243
+ **When** every section except the last sets `hasBottomBorder`
244
+ **Then** each is separated by a divider with matching bottom padding, and the
245
+ last one closes flush.
246
+
247
+ **Given** `variant="table"` together with `hasBottomBorder`
248
+ **When** it renders
249
+ **Then** only the divider is added — the root stays flush, with no padding on
250
+ any side.
251
+
252
+ ### The header
253
+
254
+ **Given** no `SectionHeader` child
255
+ **When** the section renders
256
+ **Then** there is no header row and the content is the section's only child.
257
+ There is no `hasHeader` flag: the part is simply omitted.
258
+
259
+ **Given** a `title` and `description` but no `hasDescription`
260
+ **When** it renders
261
+ **Then** only the title is shown — the description is opt-in.
262
+
263
+ **Given** `isSwitchable`
264
+ **When** it renders
265
+ **Then** a toggle switch appears at the start of the header, before the title,
266
+ carrying `switchLabel` as its accessible name. Toggling it emits
267
+ `switch-checked-change`; it never expands or collapses the section.
268
+
269
+ **Given** `extras` and `actions`
270
+ **When** it renders
271
+ **Then** `extras` sit inline immediately after the title and `actions` are
272
+ pushed to the inline end of the row, before the collapse trigger. The push
273
+ comes from the flex-grow wrapper around `title` / `description` / `extras`.
274
+
275
+ **Given** a header with `children` but no `title`, `description`, or `extras`
276
+ **When** it renders
277
+ **Then** that wrapper is not rendered at all, so `children` start at the inline
278
+ start of the row — this is what lets a consumer-supplied heading take the
279
+ title's place (see accessibility). Because nothing then grows, `actions`
280
+ follow `children` immediately rather than sitting at the inline end, unless the
281
+ consumer's own content grows (`flex-1`).
282
+
283
+ ### Collapsing
284
+
285
+ **Given** `isCollapsible` on a header that is **not** inside a collapsible
286
+ `AccordionContainer`
287
+ **When** it renders
288
+ **Then** no trigger appears — `AccordionContainer.Trigger` renders `null`
289
+ outside a collapsible container, matching the design's `isCollapsable=false`
290
+ state, which has no disclosure UI at all.
291
+
292
+ **Given** a header with `isCollapsible` inside
293
+ `<AccordionContainer collapsible defaultOpen>`
294
+ **When** it renders
295
+ **Then** the trigger is shown expanded (`aria-expanded="true"`) and the content
296
+ wrapped in `AccordionContainer.Content` is visible — the design's
297
+ `true-expanded` state.
298
+
299
+ **Given** the same composition with `defaultOpen={false}`
300
+ **When** it renders
301
+ **Then** the trigger reads `aria-expanded="false"` and the panel is collapsed —
302
+ the design's `true-collapsed` state.
303
+
304
+ **When** the trigger is activated
305
+ **Then** the panel animates its height and the chevron rotates; the header,
306
+ including the switch and actions, stays visible throughout.
307
+
308
+ ### Composition
309
+
310
+ **Given** a `render` prop on any part
311
+ **When** it renders
312
+ **Then** the element is replaced by the supplied element/component with props
313
+ and classes merged (Base UI composition) — e.g. rendering the root as an
314
+ `<article>`.
315
+
316
+ **Given** a `SectionHeader` or `SectionContent` rendered outside a `Section`
317
+ **When** it renders
318
+ **Then** it falls back to the `column1` layout rather than failing.
319
+
320
+ ## Accessibility
321
+
322
+ ## Roles and semantics
323
+
324
+ - The root renders a real `<section>` element. A `<section>` only becomes a
325
+ `region` landmark once it has an accessible name, so give it one whenever the
326
+ band is genuinely navigable content:
327
+
328
+ ```tsx
329
+ <Section aria-labelledby="protection-heading">…</Section>
330
+ ```
331
+
332
+ Do not name every section — an unnamed `<section>` is a generic grouping and
333
+ stays out of the landmark list, which is the right default for decorative
334
+ bands.
335
+
336
+ - The header title is a `<p>`, not a heading. A section's place in the document
337
+ outline depends on the page around it, so guessing a level (`h2`? `h3`?)
338
+ would produce a broken hierarchy in most compositions. When the band really
339
+ is a document section, supply your own heading through the header's
340
+ `children` slot (not `render` — that replaces the entire header row,
341
+ wrapping the switch, title, description, actions, and collapse trigger in
342
+ the heading element), omit `title` so you don't render two titles, match the
343
+ title's text scale yourself (`text-xl leading-6 font-medium
344
+ text-[var(--ui-text-on-surface-primary)]` — no exported class), and point
345
+ the root's `aria-labelledby` at it. With `title`, `description`, and `extras`
346
+ all omitted, the header renders no flex-grow wrapper at all, so give the
347
+ heading `min-w-0 flex-1` if the header also carries `actions` and they should
348
+ stay at the inline end.
349
+
350
+ - The `description` is ordinary text, not a description role. If it should name
351
+ or describe the region for assistive technology, wire it up explicitly with
352
+ `aria-describedby`.
353
+
354
+ ## Keyboard
355
+
356
+ - The section itself is not focusable and imposes no keyboard behavior.
357
+ - Focus order follows DOM order: the header switch, then anything focusable in
358
+ `extras`, then anything in the header's `children` slot, then `actions`,
359
+ then the collapse trigger, then the content. Nothing is trapped or
360
+ re-ordered.
361
+ - The collapse trigger is a real `<button>` supplied by `AccordionContainer`
362
+ (Base UI Collapsible): `Tab` reaches it and `Enter` / `Space` toggle the
363
+ panel. Its `aria-expanded` and `aria-controls` are managed by the primitive.
364
+ - Collapsed content is hidden from the accessibility tree, so it is skipped by
365
+ both `Tab` and virtual-cursor navigation.
366
+
367
+ ## Screen reader
368
+
369
+ - Icon-only controls in `actions` must supply their own accessible name; the
370
+ section adds none.
371
+ - The collapse trigger has no visible label, so it relies on `collapseLabel`
372
+ (default `'Collapse section'`). Override it with something specific when a
373
+ page stacks several collapsible sections — "Collapse section" three times in
374
+ a row is not navigable.
375
+ - The header switch likewise relies on `switchLabel` (default
376
+ `'Toggle section'`); override it per section for the same reason.
377
+ - The title may be visually truncated. Truncation is visual only — the full
378
+ string stays in the accessible text — but keep it short enough to be
379
+ meaningful.
380
+
381
+ ## Contrast
382
+
383
+ - The title uses `--ui-text-on-surface-primary` and the description
384
+ `--ui-text-on-surface-secondary`, both against the page surface. Both meet
385
+ WCAG AA in every shipped brand and in both light and dark themes.
386
+ - The `hasBottomBorder` divider uses `--ui-border-on-surface-divider`. It is a
387
+ decorative separator, not a meaningful boundary, so it is exempt from the 3:1
388
+ non-text contrast requirement — the grouping is also conveyed by the header
389
+ and the spacing.
390
+
391
+ ## Localization
392
+
393
+ - Every string the component renders on its own — `switchLabel` and
394
+ `collapseLabel` — is a prop whose literal exists only as that prop's default.
395
+ `title`, `description`, `extras`, `actions`, and the content are all
396
+ consumer-supplied.
397
+ - Layout uses logical spacing and a logical grid only, so the band mirrors
398
+ correctly under `dir="rtl"`: the switch and title sit at the inline start,
399
+ actions and the collapse trigger at the inline end, and the 70/30 split
400
+ reverses. The trigger's chevron flips through `AccordionContainer`'s own
401
+ `rtl:` variant.