@boostdev/design-system-components 2.7.1 → 2.11.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 (535) hide show
  1. package/AGENTS.md +54 -46
  2. package/README.md +34 -20
  3. package/dist/client.cjs +1317 -779
  4. package/dist/client.css +1029 -812
  5. package/dist/client.d.cts +88 -26
  6. package/dist/client.d.ts +88 -26
  7. package/dist/client.js +1278 -732
  8. package/dist/index.cjs +1317 -779
  9. package/dist/index.css +1029 -812
  10. package/dist/index.d.cts +88 -26
  11. package/dist/index.d.ts +88 -26
  12. package/dist/index.js +1278 -732
  13. package/dist/web-components/chunk-2OLVQUBU.js +193 -0
  14. package/dist/web-components/chunk-3AY2YKCM.js +223 -0
  15. package/dist/web-components/chunk-3WAV6MDN.js +212 -0
  16. package/dist/web-components/{chunk-CZBIVR4V.js → chunk-47AT5KZD.js} +88 -16
  17. package/dist/web-components/chunk-4A2YYTYN.js +93 -0
  18. package/dist/web-components/{chunk-Q4T5BJT6.js → chunk-62NK3ZSC.js} +18 -3
  19. package/dist/web-components/chunk-66M6ETWD.js +77 -0
  20. package/dist/web-components/{chunk-NCPQ7AF3.js → chunk-6G22I2CK.js} +18 -3
  21. package/dist/web-components/{chunk-QDST57JC.js → chunk-7ZOJ7N4E.js} +14 -4
  22. package/dist/web-components/{chunk-5R6IFELV.js → chunk-AIBOHNDU.js} +11 -1
  23. package/dist/web-components/{chunk-ITHLKR7Q.js → chunk-AP4RDUL2.js} +16 -5
  24. package/dist/web-components/{chunk-QWPACK5L.js → chunk-BPYKZVDK.js} +11 -1
  25. package/dist/web-components/{chunk-YLVTEY23.js → chunk-BTCMJQKB.js} +53 -21
  26. package/dist/web-components/chunk-CUKQ2L5B.js +245 -0
  27. package/dist/web-components/chunk-DIZDCL7Z.js +14 -0
  28. package/dist/web-components/{chunk-PC3IOQAH.js → chunk-DV5T43ZC.js} +27 -7
  29. package/dist/web-components/{chunk-2QA62WCQ.js → chunk-EF7IVYTY.js} +10 -0
  30. package/dist/web-components/{chunk-L3XHOMN6.js → chunk-F3ZDNHZZ.js} +26 -1
  31. package/dist/web-components/chunk-FEDABOR5.js +248 -0
  32. package/dist/web-components/{chunk-6I2DBFQ7.js → chunk-HGFCJXOQ.js} +36 -5
  33. package/dist/web-components/{chunk-SOQQ7RVJ.js → chunk-IPGHUCJT.js} +23 -8
  34. package/dist/web-components/chunk-ITD2MV5K.js +392 -0
  35. package/dist/web-components/{chunk-CM3KYZ6Z.js → chunk-JH6LQKLK.js} +78 -6
  36. package/dist/web-components/chunk-JMCXAAFK.js +120 -0
  37. package/dist/web-components/{chunk-KUI55GFB.js → chunk-JUPCZVVW.js} +50 -18
  38. package/dist/web-components/chunk-JV5QT2OU.js +146 -0
  39. package/dist/web-components/{chunk-3GFWLSLS.js → chunk-KA3VPKMY.js} +29 -6
  40. package/dist/web-components/{chunk-CR5PGUHV.js → chunk-KJGRFDFI.js} +26 -11
  41. package/dist/web-components/{chunk-PY62FTRW.js → chunk-KZPRFY5P.js} +68 -33
  42. package/dist/web-components/{chunk-X46KL5BK.js → chunk-LDIPCTRN.js} +18 -1
  43. package/dist/web-components/chunk-M3ECULRH.js +174 -0
  44. package/dist/web-components/chunk-NBN2ENWJ.js +90 -0
  45. package/dist/web-components/chunk-NIN3JO6Q.js +189 -0
  46. package/dist/web-components/{chunk-2FGATTGT.js → chunk-NTQ4TCUT.js} +76 -55
  47. package/dist/web-components/chunk-OY74D4X6.js +302 -0
  48. package/dist/web-components/{chunk-3S42DZ7W.js → chunk-P24JYC5V.js} +7 -0
  49. package/dist/web-components/{chunk-BKIHQYJR.js → chunk-PXPPKCLT.js} +17 -2
  50. package/dist/web-components/{chunk-TQ7IQ4GZ.js → chunk-QEF2IRID.js} +71 -29
  51. package/dist/web-components/chunk-QZAIRJ75.js +111 -0
  52. package/dist/web-components/{chunk-6I3CFC26.js → chunk-RSZ3BWBK.js} +20 -5
  53. package/dist/web-components/chunk-RVF7W653.js +101 -0
  54. package/dist/web-components/chunk-SEO2F5KJ.js +234 -0
  55. package/dist/web-components/{chunk-VMMVWLXL.js → chunk-SFZ6Q4BP.js} +10 -0
  56. package/dist/web-components/{chunk-LY62SAVN.js → chunk-SYNLFKD3.js} +12 -2
  57. package/dist/web-components/chunk-TMWXRHGF.js +192 -0
  58. package/dist/web-components/{chunk-65JXQOBA.js → chunk-U3YZE6R6.js} +51 -7
  59. package/dist/web-components/chunk-UO7ROSHD.js +424 -0
  60. package/dist/web-components/chunk-VANAKB6D.js +152 -0
  61. package/dist/web-components/{chunk-PXZWYO6Z.js → chunk-VED2DFJ6.js} +108 -29
  62. package/dist/web-components/chunk-W6H5ID2U.js +161 -0
  63. package/dist/web-components/{chunk-57TRNCWQ.js → chunk-WFVKU4GX.js} +22 -11
  64. package/dist/web-components/{chunk-OQTRTMAB.js → chunk-WIBAN7KP.js} +10 -0
  65. package/dist/web-components/chunk-XI7KRAH7.js +54 -0
  66. package/dist/web-components/{chunk-F5E3IT7G.js → chunk-XIZWAWMJ.js} +50 -11
  67. package/dist/web-components/{chunk-FXURM6D5.js → chunk-YFAXGRPR.js} +10 -0
  68. package/dist/web-components/globals.js +1 -1
  69. package/dist/web-components/index.d.ts +77 -707
  70. package/dist/web-components/index.js +339 -2066
  71. package/dist/web-components/interaction/bds-accordion-item.js +1 -1
  72. package/dist/web-components/interaction/bds-accordion.js +1 -1
  73. package/dist/web-components/interaction/bds-button.d.ts +10 -2
  74. package/dist/web-components/interaction/bds-button.js +1 -1
  75. package/dist/web-components/interaction/bds-collapsible.d.ts +7 -2
  76. package/dist/web-components/interaction/bds-collapsible.js +1 -1
  77. package/dist/web-components/interaction/bds-dialog.d.ts +11 -3
  78. package/dist/web-components/interaction/bds-dialog.js +1 -1
  79. package/dist/web-components/interaction/bds-drawer.d.ts +7 -1
  80. package/dist/web-components/interaction/bds-drawer.js +1 -1
  81. package/dist/web-components/interaction/bds-dropdown-menu-item.d.ts +51 -0
  82. package/dist/web-components/interaction/bds-dropdown-menu-item.js +7 -0
  83. package/dist/web-components/interaction/bds-dropdown-menu.d.ts +70 -0
  84. package/dist/web-components/interaction/bds-dropdown-menu.js +7 -0
  85. package/dist/web-components/interaction/bds-popover.d.ts +14 -3
  86. package/dist/web-components/interaction/bds-popover.js +1 -1
  87. package/dist/web-components/interaction/bds-skip-link.js +1 -1
  88. package/dist/web-components/interaction/bds-tab-panel.js +1 -1
  89. package/dist/web-components/interaction/bds-tab.js +1 -1
  90. package/dist/web-components/interaction/bds-tabs.d.ts +1 -0
  91. package/dist/web-components/interaction/bds-tabs.js +1 -1
  92. package/dist/web-components/interaction/bds-toast-provider.js +1 -1
  93. package/dist/web-components/interaction/bds-tooltip.d.ts +19 -3
  94. package/dist/web-components/interaction/bds-tooltip.js +1 -1
  95. package/dist/web-components/interaction/form/bds-checkbox-group.d.ts +83 -0
  96. package/dist/web-components/interaction/form/bds-checkbox-group.js +7 -0
  97. package/dist/web-components/interaction/form/bds-checkbox.d.ts +6 -0
  98. package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
  99. package/dist/web-components/interaction/form/bds-combobox.d.ts +18 -0
  100. package/dist/web-components/interaction/form/bds-combobox.js +1 -1
  101. package/dist/web-components/interaction/form/bds-field-group.d.ts +89 -0
  102. package/dist/web-components/interaction/form/bds-field-group.js +7 -0
  103. package/dist/web-components/interaction/form/bds-file-input.d.ts +1 -1
  104. package/dist/web-components/interaction/form/bds-file-input.js +1 -1
  105. package/dist/web-components/interaction/form/bds-form-input.d.ts +92 -0
  106. package/dist/web-components/interaction/form/bds-form-input.js +7 -0
  107. package/dist/web-components/interaction/form/bds-number-input.d.ts +18 -1
  108. package/dist/web-components/interaction/form/bds-number-input.js +1 -1
  109. package/dist/web-components/interaction/form/bds-radio-group.d.ts +81 -0
  110. package/dist/web-components/interaction/form/bds-radio-group.js +7 -0
  111. package/dist/web-components/interaction/form/bds-radio.d.ts +34 -6
  112. package/dist/web-components/interaction/form/bds-radio.js +1 -1
  113. package/dist/web-components/interaction/form/bds-segmented-control.d.ts +4 -4
  114. package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
  115. package/dist/web-components/interaction/form/bds-select.d.ts +22 -1
  116. package/dist/web-components/interaction/form/bds-select.js +1 -1
  117. package/dist/web-components/interaction/form/bds-slider.d.ts +42 -10
  118. package/dist/web-components/interaction/form/bds-slider.js +1 -1
  119. package/dist/web-components/interaction/form/bds-switch.d.ts +20 -0
  120. package/dist/web-components/interaction/form/bds-switch.js +1 -1
  121. package/dist/web-components/interaction/form/bds-textarea.d.ts +23 -3
  122. package/dist/web-components/interaction/form/bds-textarea.js +1 -1
  123. package/dist/web-components/layout/bds-grid-item.d.ts +63 -0
  124. package/dist/web-components/layout/bds-grid-item.js +7 -0
  125. package/dist/web-components/layout/bds-grid.d.ts +108 -0
  126. package/dist/web-components/layout/bds-grid.js +7 -0
  127. package/dist/web-components/ui/bds-alert.d.ts +16 -2
  128. package/dist/web-components/ui/bds-alert.js +1 -1
  129. package/dist/web-components/ui/bds-avatar.d.ts +2 -1
  130. package/dist/web-components/ui/bds-avatar.js +1 -1
  131. package/dist/web-components/ui/bds-badge.js +1 -1
  132. package/dist/web-components/ui/bds-breadcrumb.d.ts +3 -1
  133. package/dist/web-components/ui/bds-breadcrumb.js +1 -1
  134. package/dist/web-components/ui/bds-button-container.d.ts +52 -0
  135. package/dist/web-components/ui/bds-button-container.js +7 -0
  136. package/dist/web-components/ui/bds-button-group.d.ts +21 -0
  137. package/dist/web-components/ui/bds-button-group.js +8 -0
  138. package/dist/web-components/ui/bds-calendar.d.ts +121 -0
  139. package/dist/web-components/ui/bds-calendar.js +7 -0
  140. package/dist/web-components/ui/bds-card.d.ts +12 -3
  141. package/dist/web-components/ui/bds-card.js +1 -1
  142. package/dist/web-components/ui/bds-carousel.d.ts +98 -0
  143. package/dist/web-components/ui/bds-carousel.js +7 -0
  144. package/dist/web-components/ui/bds-description-list.js +1 -1
  145. package/dist/web-components/ui/bds-icon-wrapper.d.ts +0 -9
  146. package/dist/web-components/ui/bds-icon-wrapper.js +1 -1
  147. package/dist/web-components/ui/bds-link.js +1 -1
  148. package/dist/web-components/ui/bds-loading.js +1 -1
  149. package/dist/web-components/ui/bds-notification-banner.js +1 -1
  150. package/dist/web-components/ui/bds-pagination.d.ts +47 -0
  151. package/dist/web-components/ui/bds-pagination.js +7 -0
  152. package/dist/web-components/ui/bds-progress-circle.d.ts +3 -1
  153. package/dist/web-components/ui/bds-progress-circle.js +1 -1
  154. package/dist/web-components/ui/bds-progress.d.ts +3 -1
  155. package/dist/web-components/ui/bds-progress.js +1 -1
  156. package/dist/web-components/ui/bds-rating.js +1 -1
  157. package/dist/web-components/ui/bds-section-header.d.ts +18 -4
  158. package/dist/web-components/ui/bds-section-header.js +1 -1
  159. package/dist/web-components/ui/bds-separator.js +1 -1
  160. package/dist/web-components/ui/bds-skeleton.js +1 -1
  161. package/dist/web-components/ui/bds-table.d.ts +52 -0
  162. package/dist/web-components/ui/bds-table.js +7 -0
  163. package/dist/web-components/ui/bds-typography.d.ts +1 -0
  164. package/dist/web-components/ui/bds-typography.js +1 -1
  165. package/package.json +60 -3
  166. package/src/components/interaction/Button/Button.module.css +23 -14
  167. package/src/components/interaction/Button/Button.spec.tsx +20 -0
  168. package/src/components/interaction/Button/Button.tsx +2 -2
  169. package/src/components/interaction/Command/Command.mdx +5 -2
  170. package/src/components/interaction/Command/Command.module.css +23 -7
  171. package/src/components/interaction/Command/Command.spec.tsx +35 -0
  172. package/src/components/interaction/Command/Command.tsx +15 -4
  173. package/src/components/interaction/Command/index.ts +1 -1
  174. package/src/components/interaction/Dialog/Dialog.mdx +4 -4
  175. package/src/components/interaction/Dialog/Dialog.module.css +20 -0
  176. package/src/components/interaction/Dialog/Dialog.spec.tsx +20 -0
  177. package/src/components/interaction/Dialog/Dialog.tsx +8 -3
  178. package/src/components/interaction/Dialog/index.ts +1 -0
  179. package/src/components/interaction/Drawer/Drawer.mdx +5 -2
  180. package/src/components/interaction/Drawer/Drawer.module.css +34 -3
  181. package/src/components/interaction/Drawer/Drawer.spec.tsx +67 -1
  182. package/src/components/interaction/Drawer/Drawer.tsx +30 -12
  183. package/src/components/interaction/Drawer/index.ts +1 -0
  184. package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +2 -0
  185. package/src/components/interaction/DropdownMenu/DropdownMenu.spec.tsx +34 -0
  186. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +15 -5
  187. package/src/components/interaction/DropdownMenu/index.ts +1 -0
  188. package/src/components/interaction/Popover/Popover.mdx +6 -2
  189. package/src/components/interaction/Popover/Popover.module.css +26 -18
  190. package/src/components/interaction/Popover/Popover.spec.tsx +38 -0
  191. package/src/components/interaction/Popover/Popover.tsx +19 -5
  192. package/src/components/interaction/Popover/index.ts +1 -0
  193. package/src/components/interaction/Rating/Rating.mdx +1 -1
  194. package/src/components/interaction/Rating/Rating.module.css +2 -2
  195. package/src/components/interaction/Rating/Rating.tsx +1 -1
  196. package/src/components/interaction/Rating/index.ts +1 -0
  197. package/src/components/interaction/Toast/Toast.mdx +3 -0
  198. package/src/components/interaction/Toast/Toast.module.css +35 -5
  199. package/src/components/interaction/Toast/Toast.spec.tsx +69 -1
  200. package/src/components/interaction/Toast/Toast.tsx +15 -9
  201. package/src/components/interaction/form/Checkbox/Checkbox.mdx +3 -0
  202. package/src/components/interaction/form/Checkbox/Checkbox.module.css +13 -6
  203. package/src/components/interaction/form/Checkbox/Checkbox.spec.tsx +6 -0
  204. package/src/components/interaction/form/Checkbox/Checkbox.tsx +1 -1
  205. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +16 -1
  206. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +24 -8
  207. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.spec.tsx +32 -2
  208. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +14 -2
  209. package/src/components/interaction/form/Combobox/Combobox.mdx +11 -4
  210. package/src/components/interaction/form/Combobox/Combobox.module.css +6 -6
  211. package/src/components/interaction/form/Combobox/Combobox.spec.tsx +47 -0
  212. package/src/components/interaction/form/Combobox/Combobox.tsx +10 -5
  213. package/src/components/interaction/form/FieldGroup/FieldGroup.mdx +9 -10
  214. package/src/components/interaction/form/FieldGroup/FieldGroup.module.css +57 -23
  215. package/src/components/interaction/form/FieldGroup/FieldGroup.spec.tsx +129 -7
  216. package/src/components/interaction/form/FieldGroup/FieldGroup.tsx +72 -12
  217. package/src/components/interaction/form/FileInput/FileInput.mdx +9 -1
  218. package/src/components/interaction/form/FileInput/FileInput.module.css +8 -8
  219. package/src/components/interaction/form/FileInput/FileInput.spec.tsx +89 -1
  220. package/src/components/interaction/form/FileInput/FileInput.tsx +6 -2
  221. package/src/components/interaction/form/FormInput/FormInput.mdx +9 -5
  222. package/src/components/interaction/form/FormInput/FormInput.module.css +17 -8
  223. package/src/components/interaction/form/FormInput/FormInput.spec.tsx +20 -0
  224. package/src/components/interaction/form/FormInput/FormInput.tsx +7 -2
  225. package/src/components/interaction/form/NumberInput/NumberInput.mdx +5 -1
  226. package/src/components/interaction/form/NumberInput/NumberInput.module.css +6 -6
  227. package/src/components/interaction/form/NumberInput/NumberInput.spec.tsx +51 -0
  228. package/src/components/interaction/form/NumberInput/NumberInput.tsx +36 -8
  229. package/src/components/interaction/form/Radio/Radio.mdx +8 -1
  230. package/src/components/interaction/form/Radio/Radio.module.css +20 -7
  231. package/src/components/interaction/form/Radio/Radio.spec.tsx +15 -0
  232. package/src/components/interaction/form/Radio/Radio.tsx +10 -4
  233. package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +16 -1
  234. package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +24 -8
  235. package/src/components/interaction/form/RadioGroup/RadioGroup.spec.tsx +32 -2
  236. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +14 -2
  237. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +9 -3
  238. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +25 -12
  239. package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +86 -5
  240. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +44 -4
  241. package/src/components/interaction/form/Select/Select.mdx +10 -4
  242. package/src/components/interaction/form/Select/Select.module.css +4 -4
  243. package/src/components/interaction/form/Select/Select.spec.tsx +34 -0
  244. package/src/components/interaction/form/Select/Select.tsx +21 -9
  245. package/src/components/interaction/form/Slider/Slider.mdx +4 -1
  246. package/src/components/interaction/form/Slider/Slider.module.css +32 -8
  247. package/src/components/interaction/form/Slider/Slider.spec.tsx +29 -0
  248. package/src/components/interaction/form/Slider/Slider.tsx +9 -7
  249. package/src/components/interaction/form/Switch/Switch.mdx +2 -2
  250. package/src/components/interaction/form/Switch/Switch.module.css +12 -13
  251. package/src/components/interaction/form/Switch/Switch.spec.tsx +20 -0
  252. package/src/components/interaction/form/Switch/Switch.tsx +2 -1
  253. package/src/components/interaction/form/Textarea/Textarea.mdx +5 -0
  254. package/src/components/interaction/form/Textarea/Textarea.module.css +5 -5
  255. package/src/components/interaction/form/Textarea/Textarea.spec.tsx +13 -0
  256. package/src/components/interaction/form/Textarea/Textarea.tsx +3 -1
  257. package/src/components/interaction/form/atoms/Message.module.css +1 -1
  258. package/src/components/interaction/form/atoms/Message.spec.tsx +29 -0
  259. package/src/components/interaction/form/atoms/Message.tsx +1 -1
  260. package/src/components/layout/ButtonGroup/ButtonGroup.mdx +11 -0
  261. package/src/components/layout/ButtonGroup/ButtonGroup.module.css +1 -5
  262. package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +14 -0
  263. package/src/components/layout/Card/Card.mdx +6 -1
  264. package/src/components/layout/Card/Card.module.css +26 -5
  265. package/src/components/layout/Card/Card.spec.tsx +7 -0
  266. package/src/components/layout/Card/Card.tsx +4 -3
  267. package/src/components/layout/Grid/Grid.spec.tsx +44 -0
  268. package/src/components/layout/Grid/Grid.tsx +5 -5
  269. package/src/components/layout/Grid/GridItem.tsx +6 -6
  270. package/src/components/layout/Grid/masonry.ts +31 -5
  271. package/src/components/layout/Grid/useIsomorphicLayoutEffect.ts +11 -0
  272. package/src/components/layout/IconWrapper/IconWrapper.mdx +8 -2
  273. package/src/components/layout/IconWrapper/IconWrapper.module.css +9 -6
  274. package/src/components/layout/SectionHeader/SectionHeader.mdx +4 -1
  275. package/src/components/layout/SectionHeader/SectionHeader.module.css +10 -9
  276. package/src/components/ui/Accordion/Accordion.mdx +4 -1
  277. package/src/components/ui/Accordion/Accordion.module.css +2 -1
  278. package/src/components/ui/Alert/Alert.mdx +21 -4
  279. package/src/components/ui/Alert/Alert.module.css +9 -4
  280. package/src/components/ui/Alert/Alert.spec.tsx +20 -0
  281. package/src/components/ui/Avatar/Avatar.mdx +8 -3
  282. package/src/components/ui/Avatar/Avatar.module.css +13 -8
  283. package/src/components/ui/Badge/Badge.mdx +3 -1
  284. package/src/components/ui/Breadcrumb/Breadcrumb.mdx +3 -0
  285. package/src/components/ui/Breadcrumb/Breadcrumb.module.css +4 -0
  286. package/src/components/ui/Breadcrumb/Breadcrumb.spec.tsx +12 -0
  287. package/src/components/ui/Breadcrumb/Breadcrumb.tsx +11 -3
  288. package/src/components/ui/Calendar/Calendar.mdx +6 -0
  289. package/src/components/ui/Calendar/Calendar.module.css +68 -19
  290. package/src/components/ui/Calendar/Calendar.spec.tsx +139 -24
  291. package/src/components/ui/Calendar/Calendar.stories.tsx +14 -0
  292. package/src/components/ui/Calendar/Calendar.tsx +143 -154
  293. package/src/components/ui/Calendar/CalendarRange.mdx +39 -0
  294. package/src/components/ui/Calendar/CalendarRange.spec.tsx +119 -0
  295. package/src/components/ui/Calendar/CalendarRange.stories.tsx +51 -0
  296. package/src/components/ui/Calendar/CalendarRange.tsx +213 -0
  297. package/src/components/ui/Calendar/MonthGrid.tsx +141 -0
  298. package/src/components/ui/Calendar/calendar-core.spec.ts +176 -0
  299. package/src/components/ui/Calendar/calendar-core.ts +164 -0
  300. package/src/components/ui/Calendar/index.ts +1 -0
  301. package/src/components/ui/Carousel/Carousel.mdx +8 -3
  302. package/src/components/ui/Carousel/Carousel.module.css +7 -5
  303. package/src/components/ui/Carousel/Carousel.spec.tsx +67 -0
  304. package/src/components/ui/Carousel/Carousel.tsx +19 -7
  305. package/src/components/ui/Collapsible/Collapsible.mdx +17 -6
  306. package/src/components/ui/Collapsible/Collapsible.module.css +7 -2
  307. package/src/components/ui/Collapsible/Collapsible.spec.tsx +40 -0
  308. package/src/components/ui/Collapsible/Collapsible.tsx +19 -2
  309. package/src/components/ui/DescriptionList/DescriptionList.mdx +2 -0
  310. package/src/components/ui/Link/Link.mdx +4 -2
  311. package/src/components/ui/Loading/Loading.mdx +6 -3
  312. package/src/components/ui/Loading/Loading.module.css +7 -7
  313. package/src/components/ui/Loading/Loading.spec.tsx +12 -0
  314. package/src/components/ui/Loading/Loading.tsx +8 -3
  315. package/src/components/ui/NotificationBanner/NotificationBanner.mdx +4 -0
  316. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +5 -0
  317. package/src/components/ui/NotificationBanner/NotificationBanner.spec.tsx +20 -0
  318. package/src/components/ui/Pagination/Pagination.mdx +29 -7
  319. package/src/components/ui/Pagination/Pagination.module.css +15 -14
  320. package/src/components/ui/Progress/Progress.mdx +6 -2
  321. package/src/components/ui/Progress/Progress.module.css +1 -1
  322. package/src/components/ui/Progress/Progress.spec.tsx +17 -0
  323. package/src/components/ui/Progress/Progress.tsx +2 -2
  324. package/src/components/ui/ProgressCircle/ProgressCircle.mdx +8 -4
  325. package/src/components/ui/ProgressCircle/ProgressCircle.module.css +2 -2
  326. package/src/components/ui/ProgressCircle/ProgressCircle.spec.tsx +11 -1
  327. package/src/components/ui/ProgressCircle/ProgressCircle.tsx +1 -1
  328. package/src/components/ui/Separator/Separator.mdx +7 -0
  329. package/src/components/ui/Separator/Separator.module.css +1 -0
  330. package/src/components/ui/Skeleton/Skeleton.mdx +17 -0
  331. package/src/components/ui/Skeleton/Skeleton.module.css +12 -5
  332. package/src/components/ui/SkipLink/SkipLink.mdx +19 -0
  333. package/src/components/ui/SkipLink/SkipLink.module.css +8 -7
  334. package/src/components/ui/SkipLink/SkipLink.spec.tsx +28 -0
  335. package/src/components/ui/Table/Table.mdx +14 -0
  336. package/src/components/ui/Table/Table.module.css +13 -8
  337. package/src/components/ui/Table/Table.spec.tsx +56 -0
  338. package/src/components/ui/Table/Table.tsx +44 -6
  339. package/src/components/ui/Tabs/Tabs.mdx +16 -0
  340. package/src/components/ui/Tabs/Tabs.module.css +3 -3
  341. package/src/components/ui/Tabs/Tabs.spec.tsx +20 -0
  342. package/src/components/ui/Tabs/Tabs.tsx +5 -1
  343. package/src/components/ui/Tooltip/Tooltip.mdx +9 -0
  344. package/src/components/ui/Tooltip/Tooltip.module.css +32 -12
  345. package/src/components/ui/Tooltip/Tooltip.spec.tsx +56 -0
  346. package/src/components/ui/Tooltip/Tooltip.tsx +26 -7
  347. package/src/components/ui/Typography/Typography.mdx +7 -0
  348. package/src/components/ui/Typography/Typography.module.css +5 -5
  349. package/src/index.ts +7 -3
  350. package/src/stories/DesignSystem/Borders.mdx +14 -9
  351. package/src/stories/DesignSystem/Colors.mdx +43 -41
  352. package/src/stories/DesignSystem/Overview.mdx +4 -3
  353. package/src/stories/Introduction.mdx +5 -5
  354. package/src/web-components/globals.ts +7 -0
  355. package/src/web-components/index.ts +2 -0
  356. package/src/web-components/interaction/BdsAccordion.mdx +10 -1
  357. package/src/web-components/interaction/BdsButton.mdx +15 -4
  358. package/src/web-components/interaction/BdsButton.stories.tsx +1 -1
  359. package/src/web-components/interaction/BdsCollapsible.mdx +3 -3
  360. package/src/web-components/interaction/BdsDialog.mdx +12 -7
  361. package/src/web-components/interaction/BdsDialog.stories.tsx +2 -2
  362. package/src/web-components/interaction/BdsDrawer.mdx +9 -6
  363. package/src/web-components/interaction/BdsDropdownMenu.mdx +20 -1
  364. package/src/web-components/interaction/BdsPopover.mdx +7 -3
  365. package/src/web-components/interaction/BdsSkipLink.mdx +14 -1
  366. package/src/web-components/interaction/BdsTabs.mdx +18 -1
  367. package/src/web-components/interaction/BdsToastProvider.mdx +21 -3
  368. package/src/web-components/interaction/BdsTooltip.mdx +4 -4
  369. package/src/web-components/interaction/bds-accordion-item.ts +10 -0
  370. package/src/web-components/interaction/bds-accordion.spec.ts +41 -0
  371. package/src/web-components/interaction/bds-accordion.ts +28 -2
  372. package/src/web-components/interaction/bds-button.spec.ts +81 -0
  373. package/src/web-components/interaction/bds-button.ts +60 -13
  374. package/src/web-components/interaction/bds-collapsible.spec.ts +93 -2
  375. package/src/web-components/interaction/bds-collapsible.ts +49 -7
  376. package/src/web-components/interaction/bds-dialog.spec.ts +49 -0
  377. package/src/web-components/interaction/bds-dialog.ts +68 -11
  378. package/src/web-components/interaction/bds-drawer.spec.ts +93 -4
  379. package/src/web-components/interaction/bds-drawer.ts +54 -21
  380. package/src/web-components/interaction/bds-dropdown-menu-item.ts +12 -1
  381. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +63 -0
  382. package/src/web-components/interaction/bds-dropdown-menu.ts +45 -7
  383. package/src/web-components/interaction/bds-popover.spec.ts +80 -6
  384. package/src/web-components/interaction/bds-popover.ts +83 -32
  385. package/src/web-components/interaction/bds-skip-link.spec.ts +18 -0
  386. package/src/web-components/interaction/bds-skip-link.ts +29 -8
  387. package/src/web-components/interaction/bds-tab-panel.ts +10 -0
  388. package/src/web-components/interaction/bds-tab.spec.ts +25 -0
  389. package/src/web-components/interaction/bds-tab.ts +20 -5
  390. package/src/web-components/interaction/bds-tabs.spec.ts +92 -5
  391. package/src/web-components/interaction/bds-tabs.ts +42 -1
  392. package/src/web-components/interaction/bds-toast-provider.spec.ts +43 -0
  393. package/src/web-components/interaction/bds-toast-provider.ts +50 -21
  394. package/src/web-components/interaction/bds-tooltip.spec.ts +71 -0
  395. package/src/web-components/interaction/bds-tooltip.ts +100 -5
  396. package/src/web-components/interaction/form/BdsCheckbox.mdx +20 -1
  397. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +8 -0
  398. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +4 -3
  399. package/src/web-components/interaction/form/BdsCombobox.mdx +39 -2
  400. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +31 -0
  401. package/src/web-components/interaction/form/BdsFieldGroup.mdx +8 -3
  402. package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +1 -1
  403. package/src/web-components/interaction/form/BdsFileInput.mdx +26 -5
  404. package/src/web-components/interaction/form/BdsFormInput.mdx +16 -1
  405. package/src/web-components/interaction/form/BdsNumberInput.mdx +34 -2
  406. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +27 -3
  407. package/src/web-components/interaction/form/BdsRadio.mdx +39 -12
  408. package/src/web-components/interaction/form/BdsRadio.stories.tsx +26 -0
  409. package/src/web-components/interaction/form/BdsRadioGroup.mdx +9 -4
  410. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +37 -11
  411. package/src/web-components/interaction/form/BdsSelect.mdx +22 -4
  412. package/src/web-components/interaction/form/BdsSelect.stories.tsx +33 -0
  413. package/src/web-components/interaction/form/BdsSlider.mdx +36 -19
  414. package/src/web-components/interaction/form/BdsSlider.stories.tsx +24 -0
  415. package/src/web-components/interaction/form/BdsSwitch.mdx +38 -11
  416. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +16 -0
  417. package/src/web-components/interaction/form/BdsTextarea.mdx +42 -16
  418. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +21 -0
  419. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +99 -0
  420. package/src/web-components/interaction/form/bds-checkbox-group.ts +95 -9
  421. package/src/web-components/interaction/form/bds-checkbox.spec.ts +55 -0
  422. package/src/web-components/interaction/form/bds-checkbox.ts +30 -5
  423. package/src/web-components/interaction/form/bds-combobox.spec.ts +79 -0
  424. package/src/web-components/interaction/form/bds-combobox.ts +102 -17
  425. package/src/web-components/interaction/form/bds-field-group.spec.ts +158 -0
  426. package/src/web-components/interaction/form/bds-field-group.ts +167 -23
  427. package/src/web-components/interaction/form/bds-file-input.spec.ts +73 -5
  428. package/src/web-components/interaction/form/bds-file-input.ts +71 -34
  429. package/src/web-components/interaction/form/bds-form-input.spec.ts +22 -0
  430. package/src/web-components/interaction/form/bds-form-input.ts +27 -16
  431. package/src/web-components/interaction/form/bds-number-input.spec.ts +49 -0
  432. package/src/web-components/interaction/form/bds-number-input.ts +118 -29
  433. package/src/web-components/interaction/form/bds-radio-group.spec.ts +57 -0
  434. package/src/web-components/interaction/form/bds-radio-group.ts +60 -12
  435. package/src/web-components/interaction/form/bds-radio.spec.ts +123 -0
  436. package/src/web-components/interaction/form/bds-radio.ts +136 -23
  437. package/src/web-components/interaction/form/bds-segmented-control.spec.ts +55 -0
  438. package/src/web-components/interaction/form/bds-segmented-control.ts +81 -59
  439. package/src/web-components/interaction/form/bds-select.spec.ts +57 -0
  440. package/src/web-components/interaction/form/bds-select.ts +96 -8
  441. package/src/web-components/interaction/form/bds-slider.spec.ts +83 -0
  442. package/src/web-components/interaction/form/bds-slider.ts +181 -33
  443. package/src/web-components/interaction/form/bds-switch.spec.ts +68 -0
  444. package/src/web-components/interaction/form/bds-switch.ts +142 -41
  445. package/src/web-components/interaction/form/bds-textarea.spec.ts +71 -0
  446. package/src/web-components/interaction/form/bds-textarea.ts +109 -8
  447. package/src/web-components/layout/BdsGrid.mdx +6 -2
  448. package/src/web-components/layout/BdsGrid.stories.tsx +4 -0
  449. package/src/web-components/layout/bds-grid-item.spec.ts +21 -0
  450. package/src/web-components/layout/bds-grid-item.ts +17 -3
  451. package/src/web-components/layout/bds-grid.spec.ts +98 -0
  452. package/src/web-components/layout/bds-grid.ts +139 -19
  453. package/src/web-components/ui/BdsAlert.mdx +6 -5
  454. package/src/web-components/ui/BdsAlert.stories.tsx +6 -6
  455. package/src/web-components/ui/BdsAvatar.mdx +4 -2
  456. package/src/web-components/ui/BdsBreadcrumb.mdx +3 -2
  457. package/src/web-components/ui/BdsButtonContainer.mdx +64 -0
  458. package/src/web-components/ui/BdsButtonContainer.stories.tsx +84 -0
  459. package/src/web-components/ui/BdsCalendar.mdx +29 -4
  460. package/src/web-components/ui/BdsCalendar.stories.tsx +16 -18
  461. package/src/web-components/ui/BdsCalendarRange.mdx +71 -0
  462. package/src/web-components/ui/BdsCalendarRange.stories.tsx +31 -0
  463. package/src/web-components/ui/BdsCard.mdx +7 -3
  464. package/src/web-components/ui/BdsCard.stories.tsx +17 -1
  465. package/src/web-components/ui/BdsCarousel.mdx +40 -12
  466. package/src/web-components/ui/BdsDescriptionList.mdx +6 -1
  467. package/src/web-components/ui/BdsIconWrapper.mdx +3 -2
  468. package/src/web-components/ui/BdsLink.mdx +14 -2
  469. package/src/web-components/ui/BdsNotificationBanner.mdx +18 -0
  470. package/src/web-components/ui/BdsPagination.mdx +40 -1
  471. package/src/web-components/ui/BdsProgress.mdx +8 -2
  472. package/src/web-components/ui/BdsProgressCircle.mdx +5 -2
  473. package/src/web-components/ui/BdsRating.mdx +7 -0
  474. package/src/web-components/ui/BdsSectionHeader.mdx +22 -3
  475. package/src/web-components/ui/BdsSectionHeader.stories.tsx +15 -13
  476. package/src/web-components/ui/BdsTable.mdx +23 -2
  477. package/src/web-components/ui/BdsTable.stories.tsx +8 -2
  478. package/src/web-components/ui/BdsTypography.mdx +17 -1
  479. package/src/web-components/ui/bds-alert.spec.ts +17 -2
  480. package/src/web-components/ui/bds-alert.ts +31 -5
  481. package/src/web-components/ui/bds-avatar.spec.ts +29 -0
  482. package/src/web-components/ui/bds-avatar.ts +30 -12
  483. package/src/web-components/ui/bds-badge.spec.ts +5 -0
  484. package/src/web-components/ui/bds-badge.ts +11 -1
  485. package/src/web-components/ui/bds-breadcrumb.spec.ts +30 -0
  486. package/src/web-components/ui/bds-breadcrumb.ts +26 -4
  487. package/src/web-components/ui/bds-button-container.spec.ts +39 -0
  488. package/src/web-components/ui/bds-button-container.ts +123 -0
  489. package/src/web-components/ui/bds-button-group.spec.ts +14 -20
  490. package/src/web-components/ui/bds-button-group.ts +13 -64
  491. package/src/web-components/ui/bds-calendar-range.spec.ts +123 -0
  492. package/src/web-components/ui/bds-calendar-range.ts +307 -0
  493. package/src/web-components/ui/bds-calendar.spec.ts +176 -0
  494. package/src/web-components/ui/bds-calendar.ts +186 -344
  495. package/src/web-components/ui/bds-card.spec.ts +32 -0
  496. package/src/web-components/ui/bds-card.ts +34 -9
  497. package/src/web-components/ui/bds-carousel.spec.ts +147 -0
  498. package/src/web-components/ui/bds-carousel.ts +113 -36
  499. package/src/web-components/ui/bds-description-list.spec.ts +15 -0
  500. package/src/web-components/ui/bds-description-list.ts +37 -3
  501. package/src/web-components/ui/bds-icon-wrapper.spec.ts +12 -0
  502. package/src/web-components/ui/bds-icon-wrapper.ts +16 -15
  503. package/src/web-components/ui/bds-link.spec.ts +17 -0
  504. package/src/web-components/ui/bds-link.ts +26 -11
  505. package/src/web-components/ui/bds-loading.ts +11 -1
  506. package/src/web-components/ui/bds-notification-banner.spec.ts +13 -0
  507. package/src/web-components/ui/bds-notification-banner.ts +18 -1
  508. package/src/web-components/ui/bds-pagination.spec.ts +44 -0
  509. package/src/web-components/ui/bds-pagination.ts +39 -19
  510. package/src/web-components/ui/bds-progress-circle.spec.ts +21 -0
  511. package/src/web-components/ui/bds-progress-circle.ts +17 -5
  512. package/src/web-components/ui/bds-progress.spec.ts +21 -0
  513. package/src/web-components/ui/bds-progress.ts +19 -6
  514. package/src/web-components/ui/bds-rating.spec.ts +6 -0
  515. package/src/web-components/ui/bds-rating.ts +12 -2
  516. package/src/web-components/ui/bds-section-header.spec.ts +39 -8
  517. package/src/web-components/ui/bds-section-header.ts +47 -13
  518. package/src/web-components/ui/bds-separator.ts +10 -0
  519. package/src/web-components/ui/bds-skeleton.ts +10 -0
  520. package/src/web-components/ui/bds-table.spec.ts +63 -0
  521. package/src/web-components/ui/bds-table.ts +88 -28
  522. package/src/web-components/ui/bds-typography.spec.ts +47 -0
  523. package/src/web-components/ui/bds-typography.ts +28 -10
  524. package/src/web-components/ui/calendar-styles.ts +94 -0
  525. package/dist/web-components/chunk-5TFWOPLH.js +0 -49
  526. package/dist/web-components/chunk-7FMR53BW.js +0 -127
  527. package/dist/web-components/chunk-AGKJTMJI.js +0 -56
  528. package/dist/web-components/chunk-BQLZ7I4G.js +0 -56
  529. package/dist/web-components/chunk-IYGF6CD5.js +0 -118
  530. package/dist/web-components/chunk-QBB6ZX4R.js +0 -107
  531. package/dist/web-components/chunk-Y3POAKGS.js +0 -133
  532. package/dist/web-components/chunk-Y4MAXTMA.js +0 -80
  533. package/dist/web-components/chunk-Y7V7LM6R.js +0 -98
  534. package/src/web-components/ui/BdsButtonGroup.mdx +0 -69
  535. package/src/web-components/ui/BdsButtonGroup.stories.tsx +0 -66
@@ -6,18 +6,20 @@
6
6
  flex-direction: column;
7
7
  }
8
8
 
9
+ /* --input_* below are deprecated aliases for --formInput_*, kept working for one major. */
9
10
  .input {
10
- font-family: var(--bds-font_family--body);
11
- font-size: var(--bds-font_size--body);
12
- padding: var(--bds-space_s);
13
- border: var(--input_border, none);
11
+ font-family: var(--formInput_font-family, var(--bds-font_family--body));
12
+ font-size: var(--formInput_font-size, var(--bds-font_size--body));
13
+ padding: var(--formInput_padding, var(--bds-space_s));
14
+ border: var(--formInput_border, var(--input_border, none));
14
15
  --bdc_color: currentcolor;
15
16
  --bdc-outline_radius: var(--bds-border_radius--full);
16
17
 
17
- border-radius: var(--input_radius, var(--bdc-outline_radius));
18
- box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--input_shadow, var(--bdc-outline_shadow));
19
- color: var(--input_color, var(--bds-color_on-bg));
20
- background-color: var(--input_color_bg, var(--bds-color_bg));
18
+ border-radius: var(--formInput_radius, var(--input_radius, var(--bdc-outline_radius)));
19
+ box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color),
20
+ var(--formInput_shadow, var(--input_shadow, var(--bdc-outline_shadow)));
21
+ color: var(--formInput_color, var(--input_color, var(--bds-color_on-bg)));
22
+ background-color: var(--formInput_color_bg, var(--input_color_bg, var(--bds-color_bg)));
21
23
  transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
22
24
  background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
23
25
  }
@@ -31,6 +33,13 @@
31
33
  outline-offset: var(--bds-outline_offset);
32
34
  }
33
35
 
36
+ /* Disabled — also matches when an ancestor <fieldset disabled> (e.g. a
37
+ disabled FieldGroup) propagates the disabled state to this input. */
38
+ .input:disabled {
39
+ cursor: not-allowed;
40
+ opacity: 0.5;
41
+ }
42
+
34
43
  .inputError {
35
44
  --bdc_color: var(--bdc_color--error);
36
45
  }
@@ -40,4 +40,24 @@ describe('FormInput', () => {
40
40
  render(<FormInput label="Name" name="name" disabled />);
41
41
  expect(screen.getByRole('textbox')).toBeDisabled();
42
42
  });
43
+
44
+ it('keeps the input associated with its label when a consumer id prop is passed', () => {
45
+ render(<FormInput label="Email" name="email" id="consumer-id" />);
46
+ expect(screen.getByLabelText('Email')).toBeInTheDocument();
47
+ });
48
+
49
+ it('applies aria-label from the deprecated ariaLabel prop', () => {
50
+ render(<FormInput label="Email" name="email" ariaLabel="Email address" />);
51
+ expect(screen.getByRole('textbox')).toHaveAccessibleName('Email address');
52
+ });
53
+
54
+ it('applies aria-label passed as a native attribute', () => {
55
+ render(<FormInput label="Email" name="email" aria-label="Email address" />);
56
+ expect(screen.getByRole('textbox')).toHaveAccessibleName('Email address');
57
+ });
58
+
59
+ it('prefers the deprecated ariaLabel prop over a native aria-label when both are passed', () => {
60
+ render(<FormInput label="Email" name="email" ariaLabel="Deprecated label" aria-label="Native label" />);
61
+ expect(screen.getByRole('textbox')).toHaveAccessibleName('Deprecated label');
62
+ });
43
63
  });
@@ -10,6 +10,10 @@ interface FormInputProps extends WithClassName, Omit<InputHTMLAttributes<HTMLInp
10
10
  label: ReactNode;
11
11
  name: string;
12
12
  type?: Exclude<HTMLInputTypeAttribute, 'checkbox' | 'radio' | 'file'>;
13
+ /**
14
+ * @deprecated Use the native `aria-label` attribute instead. Kept working for backwards
15
+ * compatibility; will be removed in a later major.
16
+ */
13
17
  ariaLabel?: string;
14
18
  error?: string;
15
19
  hint?: string;
@@ -23,6 +27,7 @@ export function FormInput({
23
27
  hint,
24
28
  className,
25
29
  required,
30
+ 'aria-label': nativeAriaLabel,
26
31
  ...props
27
32
  }: FormInputProps) {
28
33
  const id = name + useId();
@@ -34,15 +39,15 @@ export function FormInput({
34
39
  <InputContainer className={cn(css.formGroup, className)}>
35
40
  <Label id={id} label={label} />
36
41
  <input
42
+ {...props}
37
43
  aria-invalid={!!error}
38
44
  aria-describedby={describedBy}
39
- aria-label={ariaLabel}
45
+ aria-label={ariaLabel ?? nativeAriaLabel}
40
46
  aria-required={required || undefined}
41
47
  id={id}
42
48
  name={name}
43
49
  required={required}
44
50
  className={cn(css.input, error && css.inputError)}
45
- {...props}
46
51
  />
47
52
  <Message inputId={id} type="error" message={error} />
48
53
  <Message inputId={id} type="hint" message={hint} />
@@ -47,6 +47,9 @@ Numeric text input with increment/decrement stepper buttons. Enforces `min`, `ma
47
47
  <tr><td>`--numberInput_stepper-bg`</td><td>`var(--bds-color_bg--subtle)`</td><td>Stepper button background</td></tr>
48
48
  <tr><td>`--numberInput_stepper-bg--hover`</td><td>`var(--bds-color_bg--subtle)`</td><td>Stepper button background on hover</td></tr>
49
49
  <tr><td>`--numberInput_stepper-opacity--hover`</td><td>`0.7`</td><td>Stepper button opacity on hover</td></tr>
50
+ <tr><td>`--numberInput_padding`</td><td>`var(--bds-space_s)`</td><td>Input padding</td></tr>
51
+ <tr><td>`--numberInput_font-size`</td><td>`var(--bds-font_size--body)`</td><td>Input font size</td></tr>
52
+ <tr><td>`--numberInput_stepper-padding`</td><td>`var(--bds-space_xs)`</td><td>Stepper button padding</td></tr>
50
53
  </tbody>
51
54
  </table>
52
55
 
@@ -54,5 +57,6 @@ Numeric text input with increment/decrement stepper buttons. Enforces `min`, `ma
54
57
  ## Accessibility
55
58
 
56
59
  - Renders `<input type="number">` — browser-native spinner support
57
- - Stepper buttons have `aria-label="Increment"` / `"Decrement"`
60
+ - Stepper buttons have `aria-label="Increase"` / `"Decrease"` by default; override the wording (e.g. for localization) with the `increaseLabel` / `decreaseLabel` props
58
61
  - Label linked via `id`/`htmlFor`
62
+ - Clearing the field or typing an intermediate value (e.g. a leading `-` while entering a negative number) is preserved rather than being coerced to `0`; `onChange` only fires once a full number has been parsed
@@ -33,9 +33,9 @@
33
33
  border: none;
34
34
  outline: none;
35
35
  font-family: var(--bds-font_family--body);
36
- font-size: var(--bds-font_size--body);
36
+ font-size: var(--numberInput_font-size, var(--bds-font_size--body));
37
37
  text-align: center;
38
- padding: var(--bds-space_s);
38
+ padding: var(--numberInput_padding, var(--bds-space_s));
39
39
  background: transparent;
40
40
  color: var(--numberInput_color, var(--bds-color_on-bg));
41
41
  min-inline-size: 0;
@@ -56,8 +56,8 @@
56
56
  display: flex;
57
57
  align-items: center;
58
58
  justify-content: center;
59
- padding: var(--bds-space_xs);
60
- margin: 1px;
59
+ padding: var(--numberInput_stepper-padding, var(--bds-space_xs));
60
+ margin: var(--bdc-outline_width);
61
61
  background-color: var(--numberInput_stepper-bg, var(--bds-color_bg--subtle));
62
62
  color: var(--numberInput_color, var(--bds-color_on-bg));
63
63
  cursor: pointer;
@@ -66,8 +66,8 @@
66
66
  }
67
67
 
68
68
  .stepper svg {
69
- width: 1rem;
70
- height: 1rem;
69
+ inline-size: 1rem;
70
+ block-size: 1rem;
71
71
  color: var(--numberInput_stepper-color, var(--bds-color_interactive));
72
72
  }
73
73
 
@@ -1,7 +1,23 @@
1
+ import { useState } from 'react';
1
2
  import { render, screen } from '@testing-library/react';
2
3
  import userEvent from '@testing-library/user-event';
3
4
  import { NumberInput } from './NumberInput';
4
5
 
6
+ function ControlledHarness({ initial, onChange }: { initial: number; onChange?: (value: number) => void }) {
7
+ const [value, setValue] = useState(initial);
8
+ return (
9
+ <NumberInput
10
+ label="Qty"
11
+ name="qty"
12
+ value={value}
13
+ onChange={next => {
14
+ setValue(next);
15
+ onChange?.(next);
16
+ }}
17
+ />
18
+ );
19
+ }
20
+
5
21
  describe('NumberInput', () => {
6
22
  it('renders a number input with label', () => {
7
23
  render(<NumberInput label="Quantity" name="qty" />);
@@ -46,4 +62,39 @@ describe('NumberInput', () => {
46
62
  expect(screen.getByRole('button', { name: 'Increase' })).toBeDisabled();
47
63
  expect(screen.getByRole('button', { name: 'Decrease' })).toBeDisabled();
48
64
  });
65
+
66
+ it('supports custom stepper labels via increaseLabel/decreaseLabel', () => {
67
+ render(<NumberInput label="Qty" name="qty" increaseLabel="Verhogen" decreaseLabel="Verlagen" />);
68
+ expect(screen.getByRole('button', { name: 'Verhogen' })).toBeInTheDocument();
69
+ expect(screen.getByRole('button', { name: 'Verlagen' })).toBeInTheDocument();
70
+ });
71
+
72
+ it('allows clearing a controlled value instead of forcing it back to 0', async () => {
73
+ const onChange = vi.fn();
74
+ render(<ControlledHarness initial={5} onChange={onChange} />);
75
+ const input = screen.getByRole('spinbutton');
76
+ await userEvent.clear(input);
77
+ expect(input).toHaveValue(null);
78
+ expect(onChange).not.toHaveBeenCalledWith(0);
79
+ });
80
+
81
+ it('allows typing a negative number into a controlled field', async () => {
82
+ const onChange = vi.fn();
83
+ render(<ControlledHarness initial={5} onChange={onChange} />);
84
+ const input = screen.getByRole('spinbutton');
85
+ await userEvent.clear(input);
86
+ await userEvent.type(input, '-5');
87
+ expect(input).toHaveValue(-5);
88
+ expect(onChange).toHaveBeenCalledWith(-5);
89
+ expect(onChange).not.toHaveBeenCalledWith(0);
90
+ });
91
+
92
+ it('allows clearing an uncontrolled value instead of forcing it back to 0', async () => {
93
+ const onChange = vi.fn();
94
+ render(<NumberInput label="Qty" name="qty" defaultValue={5} onChange={onChange} />);
95
+ const input = screen.getByRole('spinbutton');
96
+ await userEvent.clear(input);
97
+ expect(input).toHaveValue(null);
98
+ expect(onChange).not.toHaveBeenCalledWith(0);
99
+ });
49
100
  });
@@ -1,4 +1,4 @@
1
- import {HTMLAttributes, useId, useRef, useState} from 'react';
1
+ import {HTMLAttributes, useEffect, useId, useRef, useState} from 'react';
2
2
  import css from './NumberInput.module.css';
3
3
  import {Label} from '../atoms/Label';
4
4
  import {Message} from '../atoms/Message';
@@ -18,6 +18,10 @@ interface NumberInputProps extends WithClassName, Omit<HTMLAttributes<HTMLDivEle
18
18
  error?: string;
19
19
  hint?: string;
20
20
  onChange?: (value: number) => void;
21
+ /** Accessible label for the decrement (−) stepper button. Defaults to `'Decrease'`. */
22
+ decreaseLabel?: string;
23
+ /** Accessible label for the increment (+) stepper button. Defaults to `'Increase'`. */
24
+ increaseLabel?: string;
21
25
  }
22
26
 
23
27
  export function NumberInput({
@@ -33,6 +37,8 @@ export function NumberInput({
33
37
  hint,
34
38
  onChange,
35
39
  className,
40
+ decreaseLabel = 'Decrease',
41
+ increaseLabel = 'Increase',
36
42
  ...rest
37
43
  }: Readonly<NumberInputProps>) {
38
44
  const uid = name + useId();
@@ -45,6 +51,18 @@ export function NumberInput({
45
51
  const [internalValue, setInternalValue] = useState(defaultValue ?? 0);
46
52
  const currentValue = isControlled ? value! : internalValue;
47
53
 
54
+ // Controlled mode renders the input from a local text draft instead of the raw
55
+ // numeric `value` prop directly, so the field can be cleared and intermediate
56
+ // input (an empty string while retyping) doesn't get coerced back to a number
57
+ // on every keystroke. The draft re-syncs whenever an external `value` change
58
+ // doesn't already match what's currently drafted (e.g. a consumer-side reset).
59
+ const [controlledDraft, setControlledDraft] = useState(() => (isControlled ? String(value) : ''));
60
+
61
+ useEffect(() => {
62
+ if (!isControlled) return;
63
+ setControlledDraft(prev => (parseFloat(prev) === value ? prev : String(value)));
64
+ }, [isControlled, value]);
65
+
48
66
  const clamp = (v: number): number => {
49
67
  const withMin = min !== undefined ? Math.max(min, v) : v;
50
68
  return max !== undefined ? Math.min(max, withMin) : withMin;
@@ -58,6 +76,8 @@ export function NumberInput({
58
76
  inputRef.current.value = String(next);
59
77
  inputRef.current.dispatchEvent(new Event('input', { bubbles: true }));
60
78
  }
79
+ } else {
80
+ setControlledDraft(String(next));
61
81
  }
62
82
  onChange?.(next);
63
83
  };
@@ -69,7 +89,7 @@ export function NumberInput({
69
89
  <button
70
90
  type="button"
71
91
  className={css.stepper}
72
- aria-label="Decrease"
92
+ aria-label={decreaseLabel}
73
93
  aria-controls={uid}
74
94
  disabled={disabled || (min !== undefined && currentValue <= min)}
75
95
  onClick={() => adjust(-step)}
@@ -84,7 +104,7 @@ export function NumberInput({
84
104
  id={uid}
85
105
  type="number"
86
106
  name={name}
87
- {...(isControlled ? { value } : { defaultValue })}
107
+ {...(isControlled ? { value: controlledDraft } : { defaultValue })}
88
108
  min={min}
89
109
  max={max}
90
110
  step={step}
@@ -93,16 +113,24 @@ export function NumberInput({
93
113
  aria-describedby={describedBy}
94
114
  className={cn(css.input, error ? css.inputError : undefined)}
95
115
  onChange={e => {
96
- const v = parseFloat(e.target.value);
97
- const safe = isNaN(v) ? 0 : v;
98
- if (!isControlled) setInternalValue(safe);
99
- onChange?.(safe);
116
+ // `validity.badInput` is true while the user is mid-typing text the
117
+ // browser can't parse yet (e.g. a lone '-' or a trailing '.'). Leave
118
+ // the field's own editing buffer untouched instead of forcing it back
119
+ // to the last committed value on every keystroke.
120
+ if (e.target.validity.badInput) return;
121
+ const raw = e.target.value;
122
+ if (isControlled) setControlledDraft(raw);
123
+ if (raw === '') return; // field genuinely cleared - don't coerce to 0
124
+ const parsed = parseFloat(raw);
125
+ if (Number.isNaN(parsed)) return;
126
+ if (!isControlled) setInternalValue(parsed);
127
+ onChange?.(parsed);
100
128
  }}
101
129
  />
102
130
  <button
103
131
  type="button"
104
132
  className={css.stepper}
105
- aria-label="Increase"
133
+ aria-label={increaseLabel}
106
134
  aria-controls={uid}
107
135
  disabled={disabled || (max !== undefined && currentValue >= max)}
108
136
  onClick={() => adjust(step)}
@@ -47,8 +47,14 @@ Single-select option within a group. Renders a styled native `<input type="radio
47
47
  </thead>
48
48
  <tbody>
49
49
  <tr><td>`--radio_color-active`</td><td>`var(--bdc-color_active)`</td><td>Selected fill and border colour</td></tr>
50
- <tr><td>`--radio_color-on-active`</td><td>`var(--bdc-color_on-active)`</td><td>Inner dot colour</td></tr>
50
+ <tr><td>`--radio_color_bg`</td><td>`var(--bds-color_bg)`</td><td>Inner dot colour (the cut-out centre of the selected fill) and unselected background</td></tr>
51
51
  <tr><td>`--radio_description-color`</td><td>`var(--bds-color_on-bg--subtle)`</td><td>Description text colour</td></tr>
52
+ <tr><td>`--radio_size`</td><td>`calc(var(--bds-space_s) * 2)`</td><td>Input diameter</td></tr>
53
+ <tr><td>`--radio_offset`</td><td>`0.2em`</td><td>Optical vertical alignment offset between the input and the label baseline</td></tr>
54
+ <tr><td>`--radio_radius`</td><td>`var(--bds-border_radius--circle)`</td><td>Input border radius</td></tr>
55
+ <tr><td>`--radio_color`</td><td>`var(--bds-color_on-bg)`</td><td>Border colour (unselected)</td></tr>
56
+ <tr><td>`--radio_border`</td><td>`none`</td><td>Additional border shorthand</td></tr>
57
+ <tr><td>`--radio_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Additional bdc shadow-tail slot</td></tr>
52
58
  </tbody>
53
59
  </table>
54
60
 
@@ -58,3 +64,4 @@ Single-select option within a group. Renders a styled native `<input type="radio
58
64
  - Native `<input type="radio">` — group semantics via shared `name`
59
65
  - Wrap groups in `<fieldset>` with a `<legend>` for a group label
60
66
  - Arrow keys move between radios in the same group
67
+ - `description`, `hint` and `error` text are all associated with the input via `aria-describedby`
@@ -1,7 +1,7 @@
1
1
  @layer boostdev.component {
2
2
  .radioGroup {
3
- --inputSize: calc(var(--bds-space_s) * 2);
4
- --labelPosition: calc(var(--inputSize) + var(--bds-space_m));
3
+ --radio_size: calc(var(--bds-space_s) * 2);
4
+ --inputSize: var(--radio_size);
5
5
 
6
6
  display: flex;
7
7
  flex-direction: column;
@@ -28,13 +28,13 @@
28
28
 
29
29
  .radio {
30
30
  flex-shrink: 0;
31
- margin-block-start: 0.2em;
32
- inline-size: var(--inputSize);
33
- block-size: var(--inputSize);
31
+ margin-block-start: var(--radio_offset, 0.2em);
32
+ inline-size: var(--radio_size);
33
+ block-size: var(--radio_size);
34
34
  color: var(--radio_color, var(--bds-color_on-bg));
35
35
  border: var(--radio_border, none);
36
36
  --bdc_color: currentcolor;
37
- --bdc-outline_radius: 50%;
37
+ --bdc-outline_radius: var(--bds-border_radius--circle);
38
38
 
39
39
  border-radius: var(--radio_radius, var(--bdc-outline_radius));
40
40
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--radio_shadow, var(--bdc-outline_shadow));
@@ -42,7 +42,8 @@
42
42
  background-color: var(--radio_color_bg, var(--bds-color_bg));
43
43
  cursor: pointer;
44
44
  position: relative;
45
- transition: --bdc_color 0.2s ease, background-color 0.2s ease;
45
+ transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
46
+ background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
46
47
  }
47
48
 
48
49
  .radio:checked {
@@ -63,6 +64,18 @@
63
64
  outline-offset: var(--bds-outline_offset);
64
65
  }
65
66
 
67
+ /* Disabled — also matches when an ancestor <fieldset disabled> (e.g. a
68
+ disabled RadioGroup/FieldGroup) propagates the disabled state. */
69
+ .radio:disabled {
70
+ cursor: not-allowed;
71
+ opacity: 0.5;
72
+ }
73
+
74
+ .radio:disabled ~ .textWrapper {
75
+ opacity: 0.5;
76
+ cursor: not-allowed;
77
+ }
78
+
66
79
  .radioError {
67
80
  --bdc_color: var(--bdc_color--error);
68
81
  }
@@ -35,4 +35,19 @@ describe('Radio', () => {
35
35
  render(<Radio label="Disabled" name="disabled" value="x" disabled />);
36
36
  expect(screen.getByRole('radio')).toBeDisabled();
37
37
  });
38
+
39
+ it('associates the description with the input via aria-describedby', () => {
40
+ render(<Radio label="Option" name="opt" value="x" description="More info about this option" />);
41
+ const radio = screen.getByRole('radio');
42
+ const describedBy = radio.getAttribute('aria-describedby');
43
+ expect(describedBy).toBeTruthy();
44
+ const description = screen.getByText('More info about this option');
45
+ expect(describedBy).toContain(description.id);
46
+ });
47
+
48
+ it('keeps the label associated with the input when a consumer id is passed', () => {
49
+ render(<Radio label="Option" name="opt" value="x" id="custom-radio-id" />);
50
+ const radio = screen.getByLabelText('Option');
51
+ expect(radio).toHaveAttribute('id', 'custom-radio-id');
52
+ });
38
53
  });
@@ -14,11 +14,13 @@ interface RadioProps extends WithClassName, Omit<InputHTMLAttributes<HTMLInputEl
14
14
  hint?: string;
15
15
  }
16
16
 
17
- export function Radio({ label, name, description, error, hint, className, ...props }: RadioProps) {
18
- const id = name + useId();
17
+ export function Radio({ label, name, description, error, hint, className, id: consumerId, ...props }: RadioProps) {
18
+ const id = consumerId ?? name + useId();
19
+ const descriptionId = id + 'description';
19
20
  const hintId = id + 'hint';
20
21
  const errorId = id + 'error';
21
- const describedBy = [error && errorId, hint && hintId].filter(Boolean).join(' ') || undefined;
22
+ const describedBy =
23
+ [description && descriptionId, error && errorId, hint && hintId].filter(Boolean).join(' ') || undefined;
22
24
 
23
25
  return (
24
26
  <InputContainer className={cn(css.radioGroup, className)}>
@@ -34,7 +36,11 @@ export function Radio({ label, name, description, error, hint, className, ...pro
34
36
  />
35
37
  <div className={css.textWrapper}>
36
38
  <Label id={id} label={label} />
37
- {description && <span className={css.description}>{description}</span>}
39
+ {description && (
40
+ <span id={descriptionId} className={css.description}>
41
+ {description}
42
+ </span>
43
+ )}
38
44
  </div>
39
45
  </div>
40
46
  <Message inputId={id} type="error" message={error} />
@@ -36,10 +36,25 @@ Groups multiple `Radio` inputs under a shared label. Renders a `<fieldset>` with
36
36
 
37
37
  <ArgTypes of={Stories} />
38
38
 
39
+ ## CSS variables
40
+
41
+ All public override tokens. Set on the RadioGroup or any ancestor; they cascade.
42
+
43
+ | Variable | Default | Description |
44
+ |----------|---------|-------------|
45
+ | `--radioGroup_gap` | `var(--bds-space_xs)` | Gap between the legend/items block and, via `--radioGroup_items-gap`, between the child radios. |
46
+ | `--radioGroup_items-gap` | `var(--bds-space_xs)` | Gap between the child radios. |
47
+ | `--radioGroup_legend-color` | `var(--bds-color_on-bg)` | Legend text colour. |
48
+ | `--radioGroup_legend-font-family` | `var(--bds-font_family--body)` | Legend font family. |
49
+ | `--radioGroup_legend-font-size` | `var(--bds-font_size--body--s)` | Legend font size. |
50
+ | `--radioGroup_legend-font-weight` | `var(--bds-font_weight--medium)` | Legend font weight. |
51
+ | `--radioGroup_legend-gap` | `var(--bds-space_xs)` | Space below the legend before the items. |
52
+ | `--radioGroup_required-color` | `var(--bds-color_error)` | Colour of the visible `*` required marker. |
53
+
39
54
  ## Accessibility
40
55
 
41
56
  - Wraps radio buttons in a `<fieldset>` with a `<legend>` — screen readers announce the group label before each option
42
57
  - `disabled` on the group sets the HTML `disabled` attribute on the `<fieldset>`, which disables all child inputs
43
- - `aria-required` is set on the `<fieldset>` when `required` is true
58
+ - When `required` is true, the legend shows a visible `*` (hidden from assistive tech via `aria-hidden`) plus a visually-hidden "(required)" span, so the fieldset's accessible name resolves to `"<legend> (required)"` (e.g. `"Preferred contact (required)"`). `aria-required` is intentionally **not** set on the `<fieldset>` it is not supported ARIA on a `role=group` element and would be ignored by assistive tech
44
59
  - Error and hint messages are linked via `aria-describedby`
45
60
  - Arrow keys move between options within the group; `Tab` moves focus out of the group
@@ -5,25 +5,41 @@
5
5
  margin: 0;
6
6
  display: flex;
7
7
  flex-direction: column;
8
- gap: var(--bds-space_xs);
8
+ gap: var(--radioGroup_gap, var(--bds-space_xs));
9
9
  }
10
10
 
11
11
  .legend {
12
- font-family: var(--bds-font_family--body);
13
- font-size: var(--bds-font_size--body--s);
14
- font-weight: var(--bds-font_weight--medium);
15
- color: var(--bds-color_on-bg);
12
+ font-family: var(--radioGroup_legend-font-family, var(--bds-font_family--body));
13
+ font-size: var(--radioGroup_legend-font-size, var(--bds-font_size--body--s));
14
+ font-weight: var(--radioGroup_legend-font-weight, var(--bds-font_weight--medium));
15
+ color: var(--radioGroup_legend-color, var(--bds-color_on-bg));
16
16
  padding: 0;
17
- margin-block-end: var(--bds-space_xs);
17
+ margin-block-end: var(--radioGroup_legend-gap, var(--bds-space_xs));
18
18
  }
19
19
 
20
20
  .required {
21
- color: var(--bds-color_error);
21
+ color: var(--radioGroup_required-color, var(--bds-color_error));
22
+ }
23
+
24
+ /* Visually hidden but still exposed to assistive tech — carries the
25
+ "required" state into the fieldset's accessible name, since the
26
+ visible asterisk above is aria-hidden and `aria-required` is not
27
+ supported ARIA on a fieldset (role=group). */
28
+ .requiredLabel {
29
+ position: absolute;
30
+ inline-size: 1px;
31
+ block-size: 1px;
32
+ padding: 0;
33
+ margin: -1px;
34
+ overflow: hidden;
35
+ clip: rect(0, 0, 0, 0);
36
+ white-space: nowrap;
37
+ border-width: 0;
22
38
  }
23
39
 
24
40
  .items {
25
41
  display: flex;
26
42
  flex-direction: column;
27
- gap: var(--bds-space_xs);
43
+ gap: var(--radioGroup_items-gap, var(--bds-space_xs));
28
44
  }
29
45
  }
@@ -54,16 +54,46 @@ describe('RadioGroup', () => {
54
54
  expect(fieldset.getAttribute('aria-describedby')).toContain(errorMsg.id);
55
55
  });
56
56
 
57
- it('marks fieldset as required when required prop is set', () => {
57
+ it('does not set the unsupported aria-required attribute on the fieldset', () => {
58
+ render(
59
+ <RadioGroup legend="Required" required>
60
+ <Radio label="Option" name="opt" value="opt" />
61
+ </RadioGroup>
62
+ );
63
+ expect(screen.getByRole('group')).not.toHaveAttribute('aria-required');
64
+ });
65
+
66
+ it('shows a visible required marker when required prop is set', () => {
58
67
  render(
59
68
  <RadioGroup legend="Required" required>
60
69
  <Radio label="Option" name="opt" value="opt" />
61
70
  </RadioGroup>
62
71
  );
63
- expect(screen.getByRole('group')).toHaveAttribute('aria-required', 'true');
64
72
  expect(screen.getByText('*')).toBeInTheDocument();
65
73
  });
66
74
 
75
+ it('conveys required state to assistive tech via the accessible group name', () => {
76
+ render(
77
+ <RadioGroup legend="Preferred contact" required>
78
+ <Radio label="Option" name="opt" value="opt" />
79
+ </RadioGroup>
80
+ );
81
+ expect(
82
+ screen.getByRole('group', { name: 'Preferred contact (required)' })
83
+ ).toBeInTheDocument();
84
+ });
85
+
86
+ it('omits the required marker and accessible required text when required is not set', () => {
87
+ render(
88
+ <RadioGroup legend="Optional contact">
89
+ <Radio label="Option" name="opt" value="opt" />
90
+ </RadioGroup>
91
+ );
92
+ expect(screen.queryByText('*')).not.toBeInTheDocument();
93
+ expect(screen.queryByText('(required)')).not.toBeInTheDocument();
94
+ expect(screen.getByRole('group', { name: 'Optional contact' })).toBeInTheDocument();
95
+ });
96
+
67
97
  it('disables the fieldset when disabled prop is set', () => {
68
98
  render(
69
99
  <RadioGroup legend="Disabled" disabled>
@@ -29,12 +29,24 @@ export function RadioGroup({
29
29
  <fieldset
30
30
  {...rest}
31
31
  className={cn(css.group, className)}
32
- aria-required={required || undefined}
33
32
  aria-describedby={describedBy}
34
33
  >
35
34
  <legend className={css.legend}>
36
35
  {legend}
37
- {required && <span className={css.required} aria-hidden="true"> *</span>}
36
+ {required && (
37
+ <>
38
+ {/* Visible-only marker — aria-hidden because `aria-required` is not
39
+ supported ARIA on a fieldset/role=group, so requiredness must be
40
+ conveyed through the legend's accessible text instead (below). The
41
+ literal `{' '}` text node sits directly in the legend (not nested
42
+ inside a span) so it survives accessible-name computation — a
43
+ leading space nested inside an element gets trimmed away when
44
+ that element's own text alternative is computed. */}
45
+ <span className={css.required} aria-hidden="true"> *</span>
46
+ {' '}
47
+ <span className={css.requiredLabel}>(required)</span>
48
+ </>
49
+ )}
38
50
  </legend>
39
51
  <div className={css.items}>{children}</div>
40
52
  <Message inputId={id} type="error" message={error} />
@@ -97,18 +97,24 @@ When `selectedIndex` is omitted, the component auto-detects the active item from
97
97
  | `--control_track-bg` | `var(--bds-color_bg--subtle)` | Track background colour (both variants) |
98
98
  | `--control_item-bg` | `transparent` | Inactive item background (outline variant) |
99
99
  | `--control_item-bg--active` | `var(--bds-color_bg)` | Active item background (outline variant) |
100
- | `--control_radius` | `var(--bds-border_radius--m)` | Border radius of the outer track |
100
+ | `--control_radius` | `var(--bds-border_radius--full)` | Border radius of the outer track |
101
+ | `--control_track-pad` | `var(--bds-space_xxs)` | Inset gap between the track edge and the thumb/indicator |
101
102
  | `--control_thumb-bg` | `var(--bds-color_interactive)` | Filled thumb colour (filled variant) |
102
- | `--control_thumb-radius` | `var(--bds-border_radius--s)` | Border radius of the thumb, indicator, and item focus ring |
103
+ | `--control_thumb-radius` | `var(--bds-border_radius--full)` | Border radius of the thumb, indicator, and item focus ring |
104
+ | `--control_thumb-shadow` | `var(--bds-shadow_s)` | Filled thumb box-shadow (filled variant) |
105
+ | `--control_item-padding` | `var(--bds-space_xs) var(--bds-space_m)` | Item padding (medium size) |
103
106
  | `--control_label-color` | `var(--bds-color_on-bg--subtle)` | Inactive item text colour |
104
107
  | `--control_label-color--active` | `var(--bds-color_on-interactive)` (filled) / `var(--bds-color_interactive)` (outline) | Active item text colour |
105
108
  | `--control_label-color--hover` | `var(--bds-color_on-bg)` | Hovered inactive item text colour |
106
109
  | `--control_indicator-color` | `var(--bds-color_interactive)` | Outline indicator border colour (outline variant) |
110
+ | `--control_indicator-width` | `2px` | Outline indicator border width (outline variant) |
107
111
 
108
112
  ## Accessibility
109
113
 
110
114
  - The container renders as `role="group"`. Provide `aria-label` when the context doesn't supply a visible label.
111
115
  - Each child is responsible for its own semantics: buttons use `aria-pressed`, links use `aria-current="page"`.
116
+ - When `selectedIndex` drives the active item and the child hasn't already set `aria-current`/`aria-pressed`/`aria-selected` itself, the component injects `aria-pressed={true}` (buttons) or `aria-current="page"` (links) onto the active child automatically.
117
+ - When neither `selectedIndex` nor an ARIA-marked child is present, no item is treated as active — the sliding thumb/indicator stay hidden instead of defaulting to the first item.
118
+ - `disabled` (on the control, or on an individual child via its own `disabled`/`aria-disabled` prop) is enforced, not just styled: the item receives `aria-disabled="true"`; `<button>` children also get the native `disabled` attribute (removing them from the tab order and blocking activation); non-button children (e.g. links) get `tabIndex={-1}` and their click is prevented.
112
119
  - The sliding thumb and indicator are `aria-hidden` — they are purely decorative.
113
- - The active item is communicated via the child's own ARIA attribute, not via the container.
114
120
  - Respects `prefers-reduced-motion` — the sliding animation is disabled when the user has opted out.