@deriv-com/dds-marketing 0.1.0 → 0.2.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 (460) hide show
  1. package/.llm/components/accordion.md +193 -0
  2. package/.llm/components/accordionitem.md +236 -0
  3. package/.llm/components/aspectratio.md +212 -0
  4. package/.llm/components/badge.md +231 -0
  5. package/.llm/components/bottomsheet.md +404 -0
  6. package/.llm/components/breadcrumb.md +197 -0
  7. package/.llm/components/breadcrumbitem.md +178 -0
  8. package/.llm/components/button.md +271 -0
  9. package/.llm/components/buttonicon.md +313 -0
  10. package/.llm/components/card.md +313 -0
  11. package/.llm/components/cardbody.md +409 -0
  12. package/.llm/components/cardbutton.md +259 -0
  13. package/.llm/components/checkbox.md +285 -0
  14. package/.llm/components/divider.md +230 -0
  15. package/.llm/components/dropdownmenu.md +453 -0
  16. package/.llm/components/filterchip.md +314 -0
  17. package/.llm/components/footer.md +408 -0
  18. package/.llm/components/footergroup.md +241 -0
  19. package/.llm/components/grid.md +659 -0
  20. package/.llm/components/icon.md +194 -0
  21. package/.llm/components/link.md +354 -0
  22. package/.llm/components/menuitem.md +218 -0
  23. package/.llm/components/navbar.md +458 -0
  24. package/.llm/components/navbaritem.md +238 -0
  25. package/.llm/components/navbarmenu.md +319 -0
  26. package/.llm/components/navbarmenugroup.md +184 -0
  27. package/.llm/components/navbarpanel.md +255 -0
  28. package/.llm/components/navbarswitcher.md +343 -0
  29. package/.llm/components/navbarswitcheroption.md +156 -0
  30. package/.llm/components/option.md +268 -0
  31. package/.llm/components/pagination.md +361 -0
  32. package/.llm/components/removablechip.md +247 -0
  33. package/.llm/components/row.md +381 -0
  34. package/.llm/components/scroller.md +470 -0
  35. package/.llm/components/searchinput.md +279 -0
  36. package/.llm/components/segmentedcontrol.md +358 -0
  37. package/.llm/components/segmentedcontrolitem.md +272 -0
  38. package/.llm/components/select.md +509 -0
  39. package/.llm/components/selectchip.md +334 -0
  40. package/.llm/components/spinner.md +222 -0
  41. package/.llm/components/stack.md +334 -0
  42. package/.llm/components/statusdot.md +205 -0
  43. package/.llm/components/subdomainnavbar.md +327 -0
  44. package/.llm/components/tab.md +291 -0
  45. package/.llm/components/table.md +660 -0
  46. package/.llm/components/tablebody.md +258 -0
  47. package/.llm/components/tablecell.md +248 -0
  48. package/.llm/components/tablehead.md +248 -0
  49. package/.llm/components/tableheadercell.md +298 -0
  50. package/.llm/components/tablerow.md +285 -0
  51. package/.llm/components/tablist.md +210 -0
  52. package/.llm/components/textarea.md +362 -0
  53. package/.llm/components/textinput.md +467 -0
  54. package/.llm/components/tooltip.md +267 -0
  55. package/.llm/components/typography.md +245 -0
  56. package/.llm/digest/accordion.md +43 -0
  57. package/.llm/digest/accordionitem.md +47 -0
  58. package/.llm/digest/aspectratio.md +47 -0
  59. package/.llm/digest/badge.md +45 -0
  60. package/.llm/digest/bottomsheet.md +69 -0
  61. package/.llm/digest/breadcrumb.md +38 -0
  62. package/.llm/digest/breadcrumbitem.md +43 -0
  63. package/.llm/digest/button.md +48 -0
  64. package/.llm/digest/buttonicon.md +61 -0
  65. package/.llm/digest/card.md +50 -0
  66. package/.llm/digest/cardbody.md +68 -0
  67. package/.llm/digest/cardbutton.md +49 -0
  68. package/.llm/digest/checkbox.md +63 -0
  69. package/.llm/digest/divider.md +52 -0
  70. package/.llm/digest/dropdownmenu.md +67 -0
  71. package/.llm/digest/filterchip.md +68 -0
  72. package/.llm/digest/footer.md +57 -0
  73. package/.llm/digest/footergroup.md +42 -0
  74. package/.llm/digest/grid.md +62 -0
  75. package/.llm/digest/icon.md +45 -0
  76. package/.llm/digest/link.md +59 -0
  77. package/.llm/digest/menuitem.md +46 -0
  78. package/.llm/digest/navbar.md +60 -0
  79. package/.llm/digest/navbaritem.md +54 -0
  80. package/.llm/digest/navbarmenu.md +54 -0
  81. package/.llm/digest/navbarmenugroup.md +40 -0
  82. package/.llm/digest/navbarpanel.md +53 -0
  83. package/.llm/digest/navbarswitcher.md +51 -0
  84. package/.llm/digest/navbarswitcheroption.md +37 -0
  85. package/.llm/digest/option.md +54 -0
  86. package/.llm/digest/pagination.md +71 -0
  87. package/.llm/digest/removablechip.md +51 -0
  88. package/.llm/digest/row.md +60 -0
  89. package/.llm/digest/scroller.md +59 -0
  90. package/.llm/digest/searchinput.md +56 -0
  91. package/.llm/digest/segmentedcontrol.md +59 -0
  92. package/.llm/digest/segmentedcontrolitem.md +59 -0
  93. package/.llm/digest/select.md +92 -0
  94. package/.llm/digest/selectchip.md +68 -0
  95. package/.llm/digest/spinner.md +52 -0
  96. package/.llm/digest/stack.md +56 -0
  97. package/.llm/digest/statusdot.md +46 -0
  98. package/.llm/digest/subdomainnavbar.md +54 -0
  99. package/.llm/digest/tab.md +60 -0
  100. package/.llm/digest/table.md +71 -0
  101. package/.llm/digest/tablebody.md +49 -0
  102. package/.llm/digest/tablecell.md +55 -0
  103. package/.llm/digest/tablehead.md +50 -0
  104. package/.llm/digest/tableheadercell.md +65 -0
  105. package/.llm/digest/tablerow.md +56 -0
  106. package/.llm/digest/tablist.md +46 -0
  107. package/.llm/digest/textarea.md +78 -0
  108. package/.llm/digest/textinput.md +95 -0
  109. package/.llm/digest/tooltip.md +58 -0
  110. package/.llm/digest/typography.md +59 -0
  111. package/.llm/index.md +86 -0
  112. package/.llm/rules.md +122 -0
  113. package/.llm/tokens.md +341 -0
  114. package/AGENTS.md +164 -0
  115. package/LICENSE +21 -0
  116. package/README.md +63 -15
  117. package/dist/components/core/accordion/Accordion.css +10 -0
  118. package/dist/components/core/accordion/Accordion.d.ts +20 -0
  119. package/dist/components/core/accordion/Accordion.js +69 -0
  120. package/dist/components/core/accordion/Accordion.types.d.ts +20 -0
  121. package/dist/components/core/accordion/Accordion.types.js +7 -0
  122. package/dist/components/core/accordion-item/AccordionItem.css +98 -0
  123. package/dist/components/core/accordion-item/AccordionItem.d.ts +44 -0
  124. package/dist/components/core/accordion-item/AccordionItem.js +63 -0
  125. package/dist/components/core/accordion-item/AccordionItem.types.d.ts +32 -0
  126. package/dist/components/core/accordion-item/AccordionItem.types.js +13 -0
  127. package/dist/components/core/accordion-item/accordion-item-impl.css +107 -0
  128. package/dist/components/core/badge/Badge.css +37 -0
  129. package/dist/components/core/badge/Badge.d.ts +37 -0
  130. package/dist/components/core/badge/Badge.js +40 -0
  131. package/dist/components/core/badge/Badge.types.d.ts +24 -0
  132. package/dist/components/core/badge/Badge.types.js +8 -0
  133. package/dist/components/core/badge/badge-impl.css +32 -0
  134. package/dist/components/core/bottom-sheet/BottomSheet.css +178 -0
  135. package/dist/components/core/bottom-sheet/BottomSheet.d.ts +22 -0
  136. package/dist/components/core/bottom-sheet/BottomSheet.js +359 -0
  137. package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +67 -0
  138. package/dist/components/core/bottom-sheet/BottomSheet.types.js +18 -0
  139. package/dist/components/core/bottom-sheet/bottom-sheet-impl.css +57 -0
  140. package/dist/components/core/breadcrumb/Breadcrumb.css +19 -0
  141. package/dist/components/core/breadcrumb/Breadcrumb.d.ts +16 -0
  142. package/dist/components/core/breadcrumb/Breadcrumb.js +22 -0
  143. package/dist/components/core/breadcrumb/Breadcrumb.types.d.ts +18 -0
  144. package/dist/components/core/breadcrumb/Breadcrumb.types.js +9 -0
  145. package/dist/components/core/breadcrumb-item/BreadcrumbItem.css +34 -0
  146. package/dist/components/core/breadcrumb-item/BreadcrumbItem.d.ts +12 -0
  147. package/dist/components/core/breadcrumb-item/BreadcrumbItem.js +15 -0
  148. package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.d.ts +22 -0
  149. package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.js +9 -0
  150. package/dist/components/core/button/Button.css +141 -0
  151. package/dist/components/core/button/Button.d.ts +25 -0
  152. package/dist/components/core/button/Button.js +28 -0
  153. package/dist/components/core/button/Button.types.d.ts +40 -0
  154. package/dist/components/core/button/Button.types.js +9 -0
  155. package/dist/components/core/button/button-impl.css +46 -0
  156. package/dist/components/core/button-icon/ButtonIcon.css +135 -0
  157. package/dist/components/core/button-icon/ButtonIcon.d.ts +34 -0
  158. package/dist/components/core/button-icon/ButtonIcon.js +117 -0
  159. package/dist/components/core/button-icon/ButtonIcon.types.d.ts +41 -0
  160. package/dist/components/core/button-icon/ButtonIcon.types.js +8 -0
  161. package/dist/components/core/card/Card.css +65 -0
  162. package/dist/components/core/card/Card.d.ts +24 -0
  163. package/dist/components/core/card/Card.js +26 -0
  164. package/dist/components/core/card/Card.types.d.ts +33 -0
  165. package/dist/components/core/card/Card.types.js +7 -0
  166. package/dist/components/core/card-body/CardBody.css +139 -0
  167. package/dist/components/core/card-body/CardBody.d.ts +62 -0
  168. package/dist/components/core/card-body/CardBody.js +97 -0
  169. package/dist/components/core/card-body/CardBody.types.d.ts +61 -0
  170. package/dist/components/core/card-body/CardBody.types.js +15 -0
  171. package/dist/components/core/card-body/card-body-impl.css +87 -0
  172. package/dist/components/core/card-button/CardButton.css +73 -0
  173. package/dist/components/core/card-button/CardButton.d.ts +27 -0
  174. package/dist/components/core/card-button/CardButton.js +37 -0
  175. package/dist/components/core/card-button/CardButton.types.d.ts +24 -0
  176. package/dist/components/core/card-button/CardButton.types.js +7 -0
  177. package/dist/components/core/card-button/card-button-impl.css +39 -0
  178. package/dist/components/core/checkbox/Checkbox.css +149 -0
  179. package/dist/components/core/checkbox/Checkbox.d.ts +21 -0
  180. package/dist/components/core/checkbox/Checkbox.js +97 -0
  181. package/dist/components/core/checkbox/Checkbox.types.d.ts +46 -0
  182. package/dist/components/core/checkbox/Checkbox.types.js +15 -0
  183. package/dist/components/core/checkbox/checkbox-impl.css +90 -0
  184. package/dist/components/core/divider/Divider.css +41 -0
  185. package/dist/components/core/divider/Divider.d.ts +46 -0
  186. package/dist/components/core/divider/Divider.js +51 -0
  187. package/dist/components/core/divider/Divider.types.d.ts +25 -0
  188. package/dist/components/core/divider/Divider.types.js +9 -0
  189. package/dist/components/core/dropdown-menu/DropdownMenu.css +146 -0
  190. package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +22 -0
  191. package/dist/components/core/dropdown-menu/DropdownMenu.js +309 -0
  192. package/dist/components/core/dropdown-menu/DropdownMenu.types.d.ts +62 -0
  193. package/dist/components/core/dropdown-menu/DropdownMenu.types.js +12 -0
  194. package/dist/components/core/dropdown-menu/dropdown-menu-impl.css +70 -0
  195. package/dist/components/core/filter-chip/FilterChip.css +149 -0
  196. package/dist/components/core/filter-chip/FilterChip.d.ts +23 -0
  197. package/dist/components/core/filter-chip/FilterChip.js +37 -0
  198. package/dist/components/core/filter-chip/FilterChip.types.d.ts +53 -0
  199. package/dist/components/core/filter-chip/FilterChip.types.js +12 -0
  200. package/dist/components/core/footer/Footer.css +104 -0
  201. package/dist/components/core/footer/Footer.d.ts +43 -0
  202. package/dist/components/core/footer/Footer.js +53 -0
  203. package/dist/components/core/footer/Footer.types.d.ts +47 -0
  204. package/dist/components/core/footer/Footer.types.js +18 -0
  205. package/dist/components/core/footer/footer-impl.css +218 -0
  206. package/dist/components/core/footer-group/FooterGroup.css +90 -0
  207. package/dist/components/core/footer-group/FooterGroup.d.ts +32 -0
  208. package/dist/components/core/footer-group/FooterGroup.js +64 -0
  209. package/dist/components/core/footer-group/FooterGroup.types.d.ts +25 -0
  210. package/dist/components/core/footer-group/FooterGroup.types.js +12 -0
  211. package/dist/components/core/footer-group/footer-group-impl.css +78 -0
  212. package/dist/components/core/icon/Icon.css +40 -0
  213. package/dist/components/core/icon/Icon.d.ts +23 -0
  214. package/dist/components/core/icon/Icon.js +79 -0
  215. package/dist/components/core/icon/Icon.types.d.ts +24 -0
  216. package/dist/components/core/icon/Icon.types.js +7 -0
  217. package/dist/components/core/link/Link.css +89 -0
  218. package/dist/components/core/link/Link.d.ts +37 -0
  219. package/dist/components/core/link/Link.js +141 -0
  220. package/dist/components/core/link/Link.types.d.ts +41 -0
  221. package/dist/components/core/link/Link.types.js +9 -0
  222. package/dist/components/core/link/link-impl.css +168 -0
  223. package/dist/components/core/menu-item/MenuItem.css +70 -0
  224. package/dist/components/core/menu-item/MenuItem.d.ts +11 -0
  225. package/dist/components/core/menu-item/MenuItem.js +26 -0
  226. package/dist/components/core/menu-item/MenuItem.types.d.ts +28 -0
  227. package/dist/components/core/menu-item/MenuItem.types.js +9 -0
  228. package/dist/components/core/navbar/Navbar.css +135 -0
  229. package/dist/components/core/navbar/Navbar.d.ts +36 -0
  230. package/dist/components/core/navbar/Navbar.js +371 -0
  231. package/dist/components/core/navbar/Navbar.types.d.ts +49 -0
  232. package/dist/components/core/navbar/Navbar.types.js +17 -0
  233. package/dist/components/core/navbar/navbar-impl.css +590 -0
  234. package/dist/components/core/navbar-item/NavbarItem.css +75 -0
  235. package/dist/components/core/navbar-item/NavbarItem.d.ts +22 -0
  236. package/dist/components/core/navbar-item/NavbarItem.js +40 -0
  237. package/dist/components/core/navbar-item/NavbarItem.types.d.ts +34 -0
  238. package/dist/components/core/navbar-item/NavbarItem.types.js +10 -0
  239. package/dist/components/core/navbar-menu/NavbarMenu.css +128 -0
  240. package/dist/components/core/navbar-menu/NavbarMenu.d.ts +5 -0
  241. package/dist/components/core/navbar-menu/NavbarMenu.js +186 -0
  242. package/dist/components/core/navbar-menu/NavbarMenu.types.d.ts +45 -0
  243. package/dist/components/core/navbar-menu/NavbarMenu.types.js +12 -0
  244. package/dist/components/core/navbar-menu/navbar-menu-impl.css +186 -0
  245. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.css +26 -0
  246. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.d.ts +17 -0
  247. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.js +22 -0
  248. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.d.ts +14 -0
  249. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.js +7 -0
  250. package/dist/components/core/navbar-panel/NavbarPanel.css +87 -0
  251. package/dist/components/core/navbar-panel/NavbarPanel.d.ts +34 -0
  252. package/dist/components/core/navbar-panel/NavbarPanel.js +46 -0
  253. package/dist/components/core/navbar-panel/NavbarPanel.types.d.ts +29 -0
  254. package/dist/components/core/navbar-panel/NavbarPanel.types.js +12 -0
  255. package/dist/components/core/navbar-panel/navbar-panel-impl.css +104 -0
  256. package/dist/components/core/navbar-panel/use-navbar-panel.d.ts +26 -0
  257. package/dist/components/core/navbar-panel/use-navbar-panel.js +135 -0
  258. package/dist/components/core/navbar-switcher/NavbarSwitcher.css +117 -0
  259. package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +20 -0
  260. package/dist/components/core/navbar-switcher/NavbarSwitcher.js +90 -0
  261. package/dist/components/core/navbar-switcher/NavbarSwitcher.types.d.ts +46 -0
  262. package/dist/components/core/navbar-switcher/NavbarSwitcher.types.js +13 -0
  263. package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +179 -0
  264. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.css +39 -0
  265. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.d.ts +16 -0
  266. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.js +19 -0
  267. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.d.ts +18 -0
  268. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.js +7 -0
  269. package/dist/components/core/option/Option.css +133 -0
  270. package/dist/components/core/option/Option.d.ts +25 -0
  271. package/dist/components/core/option/Option.js +31 -0
  272. package/dist/components/core/option/Option.types.d.ts +44 -0
  273. package/dist/components/core/option/Option.types.js +14 -0
  274. package/dist/components/core/pagination/Pagination.css +237 -0
  275. package/dist/components/core/pagination/Pagination.d.ts +30 -0
  276. package/dist/components/core/pagination/Pagination.js +406 -0
  277. package/dist/components/core/pagination/Pagination.types.d.ts +59 -0
  278. package/dist/components/core/pagination/Pagination.types.js +14 -0
  279. package/dist/components/core/pagination/pagination-impl.css +17 -0
  280. package/dist/components/core/removable-chip/RemovableChip.css +125 -0
  281. package/dist/components/core/removable-chip/RemovableChip.d.ts +25 -0
  282. package/dist/components/core/removable-chip/RemovableChip.js +36 -0
  283. package/dist/components/core/removable-chip/RemovableChip.types.d.ts +38 -0
  284. package/dist/components/core/removable-chip/RemovableChip.types.js +13 -0
  285. package/dist/components/core/search-input/SearchInput.css +205 -0
  286. package/dist/components/core/search-input/SearchInput.d.ts +5 -0
  287. package/dist/components/core/search-input/SearchInput.js +81 -0
  288. package/dist/components/core/search-input/SearchInput.types.d.ts +43 -0
  289. package/dist/components/core/search-input/SearchInput.types.js +13 -0
  290. package/dist/components/core/search-input/search-input-impl.css +20 -0
  291. package/dist/components/core/segmented-control/SegmentedControl.css +57 -0
  292. package/dist/components/core/segmented-control/SegmentedControl.d.ts +37 -0
  293. package/dist/components/core/segmented-control/SegmentedControl.js +269 -0
  294. package/dist/components/core/segmented-control/SegmentedControl.types.d.ts +38 -0
  295. package/dist/components/core/segmented-control/SegmentedControl.types.js +8 -0
  296. package/dist/components/core/segmented-control/segmented-control-impl.css +57 -0
  297. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +151 -0
  298. package/dist/components/core/segmented-control-item/SegmentedControlItem.d.ts +50 -0
  299. package/dist/components/core/segmented-control-item/SegmentedControlItem.js +101 -0
  300. package/dist/components/core/segmented-control-item/SegmentedControlItem.types.d.ts +37 -0
  301. package/dist/components/core/segmented-control-item/SegmentedControlItem.types.js +10 -0
  302. package/dist/components/core/segmented-control-item/segmented-control-item-impl.css +69 -0
  303. package/dist/components/core/select/Select.css +400 -0
  304. package/dist/components/core/select/Select.d.ts +29 -0
  305. package/dist/components/core/select/Select.js +524 -0
  306. package/dist/components/core/select/Select.types.d.ts +96 -0
  307. package/dist/components/core/select/Select.types.js +26 -0
  308. package/dist/components/core/select/select-impl.css +114 -0
  309. package/dist/components/core/select-chip/SelectChip.css +155 -0
  310. package/dist/components/core/select-chip/SelectChip.d.ts +20 -0
  311. package/dist/components/core/select-chip/SelectChip.js +273 -0
  312. package/dist/components/core/select-chip/SelectChip.types.d.ts +56 -0
  313. package/dist/components/core/select-chip/SelectChip.types.js +14 -0
  314. package/dist/components/core/select-chip/select-chip-impl.css +38 -0
  315. package/dist/components/core/spinner/Spinner.css +76 -0
  316. package/dist/components/core/spinner/Spinner.d.ts +5 -0
  317. package/dist/components/core/spinner/Spinner.js +29 -0
  318. package/dist/components/core/spinner/Spinner.types.d.ts +37 -0
  319. package/dist/components/core/spinner/Spinner.types.js +10 -0
  320. package/dist/components/core/spinner/spinner-impl.css +27 -0
  321. package/dist/components/core/status-dot/StatusDot.css +43 -0
  322. package/dist/components/core/status-dot/StatusDot.d.ts +35 -0
  323. package/dist/components/core/status-dot/StatusDot.js +46 -0
  324. package/dist/components/core/status-dot/StatusDot.types.d.ts +29 -0
  325. package/dist/components/core/status-dot/StatusDot.types.js +7 -0
  326. package/dist/components/core/status-dot/status-dot-impl.css +42 -0
  327. package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +89 -0
  328. package/dist/components/core/subdomain-navbar/SubdomainNavbar.d.ts +21 -0
  329. package/dist/components/core/subdomain-navbar/SubdomainNavbar.js +127 -0
  330. package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.d.ts +43 -0
  331. package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.js +13 -0
  332. package/dist/components/core/subdomain-navbar/subdomain-navbar-impl.css +147 -0
  333. package/dist/components/core/tab/Tab.css +113 -0
  334. package/dist/components/core/tab/Tab.d.ts +36 -0
  335. package/dist/components/core/tab/Tab.js +53 -0
  336. package/dist/components/core/tab/Tab.types.d.ts +42 -0
  337. package/dist/components/core/tab/Tab.types.js +13 -0
  338. package/dist/components/core/tab/tab-impl.css +49 -0
  339. package/dist/components/core/tab-list/TabList.css +40 -0
  340. package/dist/components/core/tab-list/TabList.d.ts +26 -0
  341. package/dist/components/core/tab-list/TabList.js +124 -0
  342. package/dist/components/core/tab-list/TabList.types.d.ts +20 -0
  343. package/dist/components/core/tab-list/TabList.types.js +7 -0
  344. package/dist/components/core/tab-list/tab-list-impl.css +56 -0
  345. package/dist/components/core/table/Table.css +40 -0
  346. package/dist/components/core/table/Table.d.ts +19 -0
  347. package/dist/components/core/table/Table.js +55 -0
  348. package/dist/components/core/table/Table.types.d.ts +59 -0
  349. package/dist/components/core/table/Table.types.js +9 -0
  350. package/dist/components/core/table/table-impl.css +75 -0
  351. package/dist/components/core/table/use-table-sort.d.ts +43 -0
  352. package/dist/components/core/table/use-table-sort.js +51 -0
  353. package/dist/components/core/table-body/TableBody.css +6 -0
  354. package/dist/components/core/table-body/TableBody.d.ts +12 -0
  355. package/dist/components/core/table-body/TableBody.js +26 -0
  356. package/dist/components/core/table-body/TableBody.types.d.ts +36 -0
  357. package/dist/components/core/table-body/TableBody.types.js +7 -0
  358. package/dist/components/core/table-cell/TableCell.css +76 -0
  359. package/dist/components/core/table-cell/TableCell.d.ts +21 -0
  360. package/dist/components/core/table-cell/TableCell.js +31 -0
  361. package/dist/components/core/table-cell/TableCell.types.d.ts +43 -0
  362. package/dist/components/core/table-cell/TableCell.types.js +7 -0
  363. package/dist/components/core/table-head/TableHead.css +6 -0
  364. package/dist/components/core/table-head/TableHead.d.ts +22 -0
  365. package/dist/components/core/table-head/TableHead.js +52 -0
  366. package/dist/components/core/table-head/TableHead.types.d.ts +39 -0
  367. package/dist/components/core/table-head/TableHead.types.js +7 -0
  368. package/dist/components/core/table-head/table-head-impl.css +51 -0
  369. package/dist/components/core/table-header-cell/TableHeaderCell.css +126 -0
  370. package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +21 -0
  371. package/dist/components/core/table-header-cell/TableHeaderCell.js +34 -0
  372. package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +56 -0
  373. package/dist/components/core/table-header-cell/TableHeaderCell.types.js +9 -0
  374. package/dist/components/core/table-header-cell/table-header-cell-impl.css +74 -0
  375. package/dist/components/core/table-row/TableRow.css +18 -0
  376. package/dist/components/core/table-row/TableRow.d.ts +17 -0
  377. package/dist/components/core/table-row/TableRow.js +32 -0
  378. package/dist/components/core/table-row/TableRow.types.d.ts +45 -0
  379. package/dist/components/core/table-row/TableRow.types.js +7 -0
  380. package/dist/components/core/table-row/table-row-impl.css +31 -0
  381. package/dist/components/core/text-area/TextArea.css +325 -0
  382. package/dist/components/core/text-area/TextArea.d.ts +13 -0
  383. package/dist/components/core/text-area/TextArea.js +133 -0
  384. package/dist/components/core/text-area/TextArea.types.d.ts +67 -0
  385. package/dist/components/core/text-area/TextArea.types.js +19 -0
  386. package/dist/components/core/text-area/text-area-impl.css +36 -0
  387. package/dist/components/core/text-input/TextInput.css +400 -0
  388. package/dist/components/core/text-input/TextInput.d.ts +5 -0
  389. package/dist/components/core/text-input/TextInput.js +130 -0
  390. package/dist/components/core/text-input/TextInput.types.d.ts +96 -0
  391. package/dist/components/core/text-input/TextInput.types.js +24 -0
  392. package/dist/components/core/text-input/text-input-impl.css +36 -0
  393. package/dist/components/core/tooltip/Tooltip.css +101 -0
  394. package/dist/components/core/tooltip/Tooltip.d.ts +51 -0
  395. package/dist/components/core/tooltip/Tooltip.js +87 -0
  396. package/dist/components/core/tooltip/Tooltip.types.d.ts +38 -0
  397. package/dist/components/core/tooltip/Tooltip.types.js +9 -0
  398. package/dist/components/core/tooltip/TooltipAnchor.d.ts +52 -0
  399. package/dist/components/core/tooltip/TooltipAnchor.js +69 -0
  400. package/dist/components/core/tooltip/tooltip-anchor.css +145 -0
  401. package/dist/components/core/tooltip/tooltip-impl.css +54 -0
  402. package/dist/components/core/tooltip/use-tooltip.d.ts +111 -0
  403. package/dist/components/core/tooltip/use-tooltip.js +189 -0
  404. package/dist/components/core/typography/Typography.css +96 -0
  405. package/dist/components/core/typography/Typography.d.ts +297 -0
  406. package/dist/components/core/typography/Typography.js +28 -0
  407. package/dist/components/core/typography/Typography.types.d.ts +40 -0
  408. package/dist/components/core/typography/Typography.types.js +7 -0
  409. package/dist/components/css-time.d.ts +20 -0
  410. package/dist/components/css-time.js +30 -0
  411. package/dist/components/given.d.ts +7 -0
  412. package/dist/components/given.js +9 -0
  413. package/dist/components/hover-open.d.ts +34 -0
  414. package/dist/components/hover-open.js +90 -0
  415. package/dist/components/index.d.ts +114 -1
  416. package/dist/components/index.js +115 -2
  417. package/dist/components/layout/aspect-ratio/AspectRatio.css +29 -0
  418. package/dist/components/layout/aspect-ratio/AspectRatio.d.ts +24 -0
  419. package/dist/components/layout/aspect-ratio/AspectRatio.js +26 -0
  420. package/dist/components/layout/aspect-ratio/AspectRatio.types.d.ts +22 -0
  421. package/dist/components/layout/aspect-ratio/AspectRatio.types.js +7 -0
  422. package/dist/components/layout/aspect-ratio/aspect-ratio-impl.css +44 -0
  423. package/dist/components/layout/grid/Grid.css +76 -0
  424. package/dist/components/layout/grid/Grid.d.ts +31 -0
  425. package/dist/components/layout/grid/Grid.js +33 -0
  426. package/dist/components/layout/grid/Grid.types.d.ts +48 -0
  427. package/dist/components/layout/grid/Grid.types.js +7 -0
  428. package/dist/components/layout/grid/grid-impl.css +62 -0
  429. package/dist/components/layout/row/Row.css +85 -0
  430. package/dist/components/layout/row/Row.d.ts +32 -0
  431. package/dist/components/layout/row/Row.js +34 -0
  432. package/dist/components/layout/row/Row.types.d.ts +45 -0
  433. package/dist/components/layout/row/Row.types.js +7 -0
  434. package/dist/components/layout/scroller/Scroller.css +59 -0
  435. package/dist/components/layout/scroller/Scroller.d.ts +34 -0
  436. package/dist/components/layout/scroller/Scroller.js +36 -0
  437. package/dist/components/layout/scroller/Scroller.types.d.ts +38 -0
  438. package/dist/components/layout/scroller/Scroller.types.js +7 -0
  439. package/dist/components/layout/scroller/scroller-impl.css +45 -0
  440. package/dist/components/layout/stack/Stack.css +73 -0
  441. package/dist/components/layout/stack/Stack.d.ts +28 -0
  442. package/dist/components/layout/stack/Stack.js +30 -0
  443. package/dist/components/layout/stack/Stack.types.d.ts +41 -0
  444. package/dist/components/layout/stack/Stack.types.js +7 -0
  445. package/dist/components/visually-hidden.d.ts +22 -0
  446. package/dist/components/visually-hidden.js +31 -0
  447. package/dist/fonts/LICENSE-inter.txt +93 -0
  448. package/dist/fonts/LICENSE-red-hat-mono.txt +93 -0
  449. package/dist/fonts/fonts.css +111 -0
  450. package/dist/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  451. package/dist/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  452. package/dist/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  453. package/dist/fonts/inter-greek-wght-normal.woff2 +0 -0
  454. package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  455. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  456. package/dist/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  457. package/dist/fonts/red-hat-mono-latin-ext-wght-normal.woff2 +0 -0
  458. package/dist/fonts/red-hat-mono-latin-wght-normal.woff2 +0 -0
  459. package/dist/marketing.css +289 -241
  460. package/package.json +18 -4
@@ -0,0 +1,509 @@
1
+ <!-- GENERATED from select.contract.json. Do not edit. -->
2
+
3
+ # Select
4
+
5
+ A control for choosing one answer from a set the reader scans. It is shut until they open it, and what it shows when shut is the answer they gave — so a form of these reads as a list of decisions rather than a list of empty fields.
6
+
7
+ On a marketing page it does two jobs, and the contract says both rather than pretending it is only one. It collects an answer a form submits — a country, a language, the kind of enquiry somebody is making. And it narrows what is already on the page — the sort on an index of articles, the market a pricing table is showing. The two differ in what happens after the answer: one is carried to a server when the visitor presses send, the other reshapes the page the moment it is taken. Nothing in the control changes between them, which is why they are one component and not two.
8
+
9
+ What it is not is navigation. A set of places a visitor can go is DropdownMenu, and the distinction matters more here than in an app: a marketing page is mostly links, so a menu drawn as a form field invites an answer nobody will submit, and a field drawn as a menu loses the answer the moment the reader expects a page to load.
10
+
11
+ ## Use when
12
+
13
+ - A form asks for one answer out of a set the visitor recognises — a country, a language, the reason they are getting in touch
14
+ - An index or a table is worth narrowing, and the choice reshapes the page rather than being submitted — the sort on a list of articles, the market a pricing table shows
15
+ - The set is long enough that showing it in full would crowd the page, which is what separates this from a row of chips or a segmented control
16
+
17
+ ## Do not use
18
+
19
+ - The set is a handful and worth comparing side by side → `SegmentedControl`
20
+ - The choices are destinations rather than answers → `DropdownMenu`
21
+ - The reader can pick more than one → nothing here does this
22
+ - The answer is not on the list, and typing one should stand → nothing here does this
23
+ - Navigation. A set of destinations drawn as a form field is a menu the visitor will answer rather than follow, and the press that should have loaded a page instead sets a value nothing reads
24
+ - Two answers at once. The box holds one, and a second choice replaces the first silently — a reader who meant to add has removed, and nothing told them
25
+ - A set of two. A box that opens to reveal yes and no is three interactions where a Switch or a pair of radio buttons is one, and the reader cannot see what they are choosing between until they have already committed to finding out
26
+ - Hiding how long a list is. A closed box says nothing about whether it holds six answers or six hundred, which is fine when the reader knows the domain and a trap when they do not — a hundred unlabelled options is a set that needs searching, and saying so is what `searchable` is
27
+
28
+ ## Anatomy
29
+
30
+ Select renders 18 elements. A token binding names the part it applies to.
31
+
32
+ - `root` — `<div>`, class `dds-select`. The control and everything that explains it, stacked. A column rather than a row, for the reason TextInput is one: a label beside its field survives one language and one width, and a marketing page is neither — it is translated, and it is read at 360 pixels as often as at 1440.
33
+
34
+ Carries the size, status and fixed attributes, which is what lets every part below respond to them without being told separately.
35
+ - `label-row` — `<div>`, class `dds-select__label-row`. Holds the label and, when there is one, the button that explains it. A row rather than a label with something inside it: the trigger of an explanation is a second control, and one control inside another is what no-nested-interactive refuses.
36
+
37
+ Always rendered, so the markup has one shape whether the field carries an explanation or not.
38
+ - `label` — `<span>`, class `dds-select__label`. What the control is for, in words, above it and always drawn.
39
+
40
+ A <span> where marketing's TextInput uses a <label>, and the reason is the element rather than a preference: a <label> claims a labelable element through htmlFor, and the thing being named here is a button, which is not one. So the association runs the other way — the button points back at this through aria-labelledby. Same words, same place, a mechanism the HTML allows.
41
+
42
+ Always, and this is the one thing about this component not open to negotiation. A placeholder is not a label: it is replaced by the answer on the first choice, so the visitor loses the question exactly when they have answered it and cannot check what they were asked.
43
+ - `label-tooltip` — `<button>`, class `dds-select__label-tooltip`. The button that reveals the explanation, drawn beside the label rather than under it.
44
+
45
+ A tab stop by intent. An explanation only a pointer can reach is one half the people filling the form never seeing it, and the cost is one stop before a field that opted into having more to say.
46
+
47
+ Its target is wider than its mark: the glyph is sized to read beside the label, and the target is sized to be hit. It paints a background on hover, which is the only thing that shows a pointer where the target actually is. Rendered only when `labelTooltip` is set.
48
+ - `required-mark` — `<span>`, class `dds-select__required-mark`. The mark beside the label saying this one cannot be skipped. Red, in `color.fg.required` rather than `color.fg.danger` — the same colour today and a separate decision, because required is not a verdict. A field marked required has not failed anything yet.
49
+
50
+ Hidden from screen readers, because aria-required already says it and hearing both says it twice. Rendered only when `required` is set.
51
+ - `optional-mark` — `<span>`, class `dds-select__optional-mark`. The word beside the label saying this one may be skipped, lowercase like its counterpart.
52
+
53
+ Not hidden from screen readers, unlike the required mark: there is no ARIA attribute for optional, so this text is the only thing carrying it. It joins the accessible name and is read as 'Country optional' — verbose, and the alternative is saying nothing at all. Rendered only when `optional` is set.
54
+ - `control` — `<div>`, class `dds-select__control`. The box the visitor aims at: the border, the ground, the corner, the height and the focus ring.
55
+
56
+ Separate from the thing inside it for the reason TextInput separates them — a box that has to contain something cannot be the something — and here it earns that separation twice over, because it is also what the list is measured against. The list is out of flow and pinned to this box's edge, so this is the one part that establishes a position for it. Move the positioning to the root and the list would clear the label row too, opening a gap the width of the words above the field.
57
+ - `field` — `<button>`, class `dds-select__field`. What the visitor presses, and the only tab stop while the list is shut. Transparent and borderless inside the box the control draws — so this element is left holding the answer, the mark beside it, and the inset that keeps them off the border.
58
+
59
+ It fills the box entirely, which is what makes the whole box pressable rather than only the part of it that is not padding. An <input> cannot contain anything, so a text field keeps its inset on the wrapper; a button can, so the inset comes here and the target grows to meet the border.
60
+ - `answer` — `<span>`, class `dds-select__answer`. The answer as a whole: the mark the chosen option carries, and its words. A box of its own because the two have to sit in a row and the words have to be cut at their end, and one element cannot do both — `text-overflow` needs a block container, and a row is not one.
61
+
62
+ Always here, with the mark inside it only when the chosen answer has one. Which is why the mark needs no part and no gate: a gap between one child and nothing is nothing, so a box with no mark in it costs no space at all.
63
+ - `value` — `<span>`, class `dds-select__value`. The answer in the words the visitor chose it by — they picked "Singapore" and should not be shown "sg". With nothing chosen the placeholder stands here instead, in quieter ink.
64
+
65
+ Set at `font.body`, the step marketing's TextInput gives the text inside a field, rather than a heavier one. What separates a given answer from a waiting placeholder here is the ink and not the weight: `color.fg.default` against `color.fg.tertiary`, which is exactly how TextInput tells a typed value from its placeholder. A package that made this one distinction twice, once by colour and once by weight, would have two conventions for the same fact.
66
+
67
+ One line, cut at its end: a box that grew to two lines would move the whole form down every time somebody picked a longer answer — and on a phone, where these forms are mostly read, that is the submit button moving under the reader's thumb.
68
+ - `trailing-icon` — `<span>`, class `dds-select__trailing-icon`. The mark that says this opens, and which way.
69
+
70
+ Inside the button rather than beside it, which is again the element: TextInput's ornaments are siblings of its field because an <input> cannot hold them, and an ornament beside a button would be a piece of the box that does not press.
71
+
72
+ Decorative to a screen reader, which is told by aria-expanded — and told it in words, where a chevron says it in a direction nobody can hear. Gone entirely when the control is fixed: a mark saying a box opens, on a box that does not, is the component contradicting itself.
73
+ - `popup` — `<div>`, class `dds-select__popup`. The floating surface: the corner, the fill, the shadow and the ceiling before it scrolls. It holds the list, the field that narrows the list where there is one, and the sentence that stands in for the list when nothing matched.
74
+
75
+ Which is why it exists at all, the list having been the surface until search arrived. A <ul> may hold options and little else, so a field inside one is a control announced as nothing and a sentence inside one is text a screen reader cannot place.
76
+
77
+ Drawn as marketing draws every floating surface — `radius.menu`, `color.border.subtle`, `elevation.surface.floating` — rather than as a card. A page already has DropdownMenu's panel on it, and two floating surfaces on one page that disagree about their corner read as two systems. Rendered only when `open` is set.
78
+ - `search` — `<div>`, class `dds-select__search`. The field that narrows the list, at the top of the surface rather than in the box. The box is a button holding the answer and a button cannot be typed into, so the typing happens up here among the answers and what the box says stays the answer.
79
+
80
+ Sticky, so it stays reachable while a long list scrolls under it — a search field that scrolls away is a search field the visitor has to scroll back for.
81
+
82
+ Inset eight at the top and either side, where the rows take four. The field has to clear the panel's corner — `radius.menu` is sixteen, and a control set four from the edge would have its own corner cutting into the surface's. Underneath it takes the rows' four, so the gap between the field and the first answer is the gap the answers keep between themselves.
83
+
84
+ A wrapper rather than the field, and what sits in it is a SearchInput, which brings the magnifier, the clear button and a query that empties in one press. Rendered only when `searchable` is set.
85
+ - `listbox` — `<ul>`, class `dds-select__listbox`. The answers on offer, or the ones that match what has been typed where a query is narrowing them.
86
+
87
+ Its own inset is the step the rows do not carry, and it is `space.inset.2xs` for a reason the package already settled: `radius.menu` less that inset is `radius.menu-item`, which is what an Option's corner takes. So the first and last rows land on the panel's inside edge and the two curves are concentric rather than merely close. Rendered only when `open` is set.
88
+ - `empty` — `<span>`, class `dds-select__empty`. What the surface says when nothing matched. A sentence rather than an empty list, because a list that vanishes reads as a control that broke while a list saying "no countries match" reads as an answer — and the visitor has to know which so they know whether to keep typing.
89
+
90
+ In the DOM whenever the list can be narrowed, and hidden while anything matches rather than arriving and leaving. A list under a query is a live region, and a node that appears is announced differently from one that was always there. Rendered only when `searchable` is set.
91
+ - `helper` — `<span>`, class `dds-select__helper`. Standing guidance under the control — what the answer affects, or where to look if none of the options seem right. It is there before anything goes wrong and stays there while the visitor decides.
92
+
93
+ On a marketing form this is often the most valuable line on the page. "This only changes which prices we show you" is the sentence that stops somebody abandoning a field they were suspicious of.
94
+
95
+ Hidden once the control has a status, because that slot belongs to the status message: guidance beside a control reporting a problem reads as though nothing were wrong. Rendered only when `helperText` is set.
96
+ - `message` — `<span>`, class `dds-select__message`. What the status means, in the colour of the status. Takes the helper's place rather than stacking beneath it, so the layout does not shift and the visitor is never reading two things that contradict each other.
97
+
98
+ It says what to do, not that something is wrong: the field is already red and the reader can see that. "Choose the country your account is registered in" is a message; "Invalid" is the component telling the visitor they have failed and leaving them there. Rendered only when `status` is set.
99
+ - `message-icon` — `<span>`, class `dds-select__message-icon`. The box the status glyph sits in, and the reason it is a part rather than a bare Icon.
100
+
101
+ Aligned to the start of the block axis, a glyph is a flex item as tall as itself — sixteen pixels against a line of type that is taller — so its middle sits above the first line's and the words beside it read as pushed down. Giving the box the line's own height puts the glyph on the line instead.
102
+
103
+ The glyph takes its colour from the text beside it and is decorative to a screen reader, the words saying the same thing. Its shape is what separates an error from a warning for a reader who cannot tell those two colours apart. Rendered only when `status` is set.
104
+
105
+ Apply these classes from the generated `selectParts` constant rather than writing the strings by hand.
106
+
107
+ ## Composition
108
+
109
+ - Can contain: `Option`
110
+ - Never contains: `Button`, `TextInput`, `Select`, `DropdownMenu`, `Card` — in children or in any prop that takes a node
111
+
112
+ ## Props
113
+
114
+ ### size — `sm` | `md` | `lg` (default `md`)
115
+
116
+ - `sm` — A filter row above an index, or a narrowing that sits in a bar rather than in a form. Desktop only: below what a finger reliably hits, which is why a filter row that has to work on a phone takes md
117
+ - `md` — The default, and what a marketing form wants. It matches TextInput at the same step, so a contact form's country field and its email field are the same height
118
+ - `lg` — A hero, a conversion band, or a form that is the whole point of the page. The step that pairs with a large Button, so the field and the thing that submits it agree
119
+
120
+ Use when: Choosing the type, the inset and the height of the box — the same three things it chooses on a TextInput, and a form mixing the two at different steps reads as two forms.
121
+
122
+ The rows in the open list follow it as far as they can. Option is drawn at two steps where this control has three, so `sm` and `md` pass straight through and `lg` holds its rows at `md`, which is the largest an answer is cut for.
123
+ Never for: Signalling importance. A larger box is a larger target and nothing else — a page that sizes one field up to say it matters has made every other field look optional
124
+
125
+ ### status — `none` | `pending` | `error` | `warning` | `success` (default `none`)
126
+
127
+ - `none` — Nothing has been checked, or the answer passed and saying so would be noise. The ordinary state, and the one a page sits in until a form is submitted
128
+ - `pending` — The answer is being checked and the outcome is not known. The control stays usable and the border does not move: a wait is not a verdict. A `statusMessage` is obliged here, because there is nowhere inside the box for a mark to go
129
+ - `error` — The answer cannot be accepted and the visitor has to choose again. The one status a marketing form reaches for often, and it arrives on submit
130
+ - `warning` — The answer is accepted but likely wrong — a country that changes what else the form asks, a region the offer is not available in
131
+ - `success` — The answer was checked against something and passed, and confirming it is worth the space. Rare here: a form that ticks every field a visitor fills is a form congratulating them for typing
132
+
133
+ Use when: The outcome of a check on the answer, and whether one is running. On a marketing page this nearly always arrives after the visitor presses send, because a landing page has nothing to check against until then
134
+ Never for: Decoration, or a permanent state. A control that always looks like a warning is telling the reader nothing, and a marketing page that paints a field red before the visitor has done anything has accused them of a mistake they have not made
135
+
136
+ ### fixed — `boolean` (default `false`)
137
+
138
+ Use when: The answer is settled and still worth reading — a region a page was entered through, a plan a link arrived with. The box keeps its ink and its border and stops opening, so a reader can see what was answered without being invited to change it.
139
+
140
+ Named for what it is rather than borrowed from the family. A text field says this with the platform's `readonly`, which the browser owns and enforces; there is no such attribute for a button, so this is the component's own.
141
+ Never for: A control nothing can be answered from, which is disabled and recedes. The difference is whether the answer is worth reading: this keeps it legible and disabled makes it too faint to read, so using one for the other loses exactly the thing the reader came for.
142
+
143
+ And decoration on a marketing page. A field drawn fixed with nothing behind it is a form pretending to have remembered something about the visitor
144
+
145
+ ### label — `string` **Required.**
146
+
147
+ Use when: Always — a control with no label is unusable by a screen reader, and on a marketing page it is also the only thing telling a visitor what is being asked before they commit to opening it. A noun phrase naming the answer, in sentence case: "Country", not "Please choose your country"
148
+ Never for: The instruction, which belongs in the placeholder, or the rule, which belongs in helperText. A label that explains has stopped naming
149
+
150
+ ### labelTooltip — `string`
151
+
152
+ Use when: A short explanation the label has no room for — why the answer is asked for, what it changes further down the form. Revealed on hover and on focus, so it costs no height
153
+ Never for: Anything the visitor needs before they open the list, which is helperText and belongs on screen. A marketing page's reader is not committed enough to go hunting for an explanation behind a glyph
154
+
155
+ ### placeholder — `string` **Required.**
156
+
157
+ Use when: Always. What the box says with nothing chosen — an instruction rather than an example, there being nothing to spell: "Select a country". Required where a text field's is optional, and the difference is what an empty one looks like: an empty text field looks empty, while an empty box with a chevron looks like it might already hold something
158
+ Never for: A fake answer. A placeholder that reads like an option makes the control look already answered, and a required set with a plausible-looking default is the commonest way a form collects a value nobody chose
159
+
160
+ ### helperText — `string`
161
+
162
+ Use when: What the visitor needs to know before they choose — what the answer affects, or where to look if none of the options seem right. On a marketing form this is often the line that decides whether the field gets answered at all: "This only changes which prices we show you" removes a reason to abandon the page
163
+ Never for: Validation results, which belong in statusMessage and appear only once something has been checked
164
+
165
+ ### value — `string`
166
+
167
+ Use when: The chosen answer, when the consumer owns it — the controlled form. The value and not the words, so a page holds "sg" while the box shows "Singapore" and the words can be reworded or translated without changing what any form submits. Which matters more here than in an app: these pages are translated, and a value that travelled as its label would change meaning with the locale
168
+
169
+ ### defaultValue — `string`
170
+
171
+ Use when: The answer the control starts on — a region guessed from where the visitor arrived, or a sort an index defaults to. Leave it out and the placeholder shows, which is what a set with no safe default wants
172
+
173
+ ### onChange — `callback` **Required.**
174
+
175
+ Use when: Always, and it is required for that reason. It hands back the value of the answer taken, each time one is taken — the value rather than an event, there being no keystroke here to read one off. It is also the only way the answer reaches the page: this draws a button rather than a <select>, so there is no form control for a browser to submit on its own
176
+ Never for: Nothing — there is no case for leaving it out. A control whose whole output arrives through one callback is not usable without it, and leaving it optional only moves the discovery to runtime. If the answer should not be changeable, that is `fixed`
177
+
178
+ ### open — `boolean`
179
+
180
+ Use when: Whether the list is showing, when the consumer owns that too. Left out, the control opens and shuts itself, which is what almost every page wants
181
+
182
+ ### defaultOpen — `boolean`
183
+
184
+ Use when: Open on first render. For a documentation page or a specimen that has to show the list without anybody pressing anything — not for a page a visitor lands on, where a list that opens by itself covers whatever is under it
185
+
186
+ ### onOpenChange — `callback`
187
+
188
+ Use when: Told when the list opens and shuts, for a page that has to react — closing something else, or holding a scroll position
189
+
190
+ ### searchable — `boolean` (default `false`)
191
+
192
+ Use when: The set is long enough that finding an answer by eye is work — countries, languages, the markets an index covers. A field opens at the top of the list and narrows it to what the visitor types, and the box below goes on showing the answer they gave rather than the letters they typed to reach it.
193
+
194
+ The typing is a way through the list and never an answer. Nothing here takes a value that is not on it
195
+ Never for: A set short enough to read at a glance. A search field over six answers is one more thing to get past before reaching what was already in front of the reader — and a letter pressed at this control already jumps to the row beginning with it, without a field to type it into
196
+
197
+ ### emptyLabel — `string` **Required when searchable=true.**
198
+
199
+ Use when: What the surface says when the query matched nothing — "No countries match" rather than a surface that empties. Required once the list can be narrowed, which is what the search field makes possible: a list that vanishes reads as a control that broke, where a sentence in its place reads as an answer
200
+ Never for: A set that arrived with nothing in it. That is a page with nothing to offer, and saying nothing matches blames a query the visitor never typed
201
+
202
+ ### required — `boolean` (default `false`)
203
+
204
+ Use when: The form cannot be submitted without an answer, and the visitor should know before they reach the end. Worth more on a marketing form than an app's: nobody is invested yet, and a form that only reveals what it needed at the last press is a form people leave
205
+ Never for: Validation. It marks and announces the control as required and nothing more — whether the answer is acceptable is still said through status and statusMessage
206
+
207
+ ### requiredMark — `text` | `asterisk` (default `text`)
208
+
209
+ - `text` — Short forms, public ones, and anywhere the label row has room. The safer default and the right one for nearly every marketing form: it needs nothing looked up and still means something read out of context
210
+ - `asterisk` — Long or dense forms where the word repeats down the page and one legend can say it once instead. Only where that legend is visible from the fields it governs
211
+
212
+ Use when: Choosing how a required control says so. Decide which state is the exception first — mark the required ones or the optional ones, whichever are fewer
213
+ Never for: Varying within one form. A page marking some labels with a word and others with a glyph reads as two conventions and teaches neither
214
+
215
+ ### optional — `boolean` (default `false`)
216
+
217
+ Use when: Most of the form is required, so the few that are not are worth marking instead. The common shape on a marketing page, where a form asks for two things it needs and one it would like
218
+ Never for: Marking every optional control on a form where most are optional — a marker on almost every label is noise
219
+
220
+ ### statusMessage — `string` **Required when status=error, or when status=warning, or when status=pending.**
221
+
222
+ Use when: Saying what the status means: what is wrong and how to fix it, what to look at, or what was confirmed
223
+ Never for: Restating the status. "Error" beside a red control says nothing the colour has not, and the colour is the part a colour-blind reader may not get
224
+
225
+ Also accepts everything from `ButtonHTMLAttributes<HTMLButtonElement>`.
226
+
227
+ ## States
228
+
229
+ States you set. Everything else is driven by the browser.
230
+
231
+ - `disabled` — The answer cannot be given from here — a set that depends on something not yet chosen, or a field a page has switched off until something else is filled in. Everything recedes: the box loses opacity and every word around it takes the disabled ink, because a label at full strength over a control nobody can use is a label promising something.
232
+ Avoid when: Only some answers are unavailable, which belongs on the options that are — disabling the control to rule out one answer removes the ones that were fine, and says why about none of them. And an answer that is settled rather than unavailable: this makes the words too faint to read, which is the opposite of what a settled answer is for. That is `fixed`.
233
+
234
+ ## Accessibility
235
+
236
+ Guaranteed by the component. Write none of it by hand: the ids these attributes point at are generated per instance, so an attribute set from outside either says the same thing twice or points at nothing.
237
+
238
+ - Announced as: `combobox`
239
+ - `Tab` — move focus, and one stop whether the list is open or shut. Nothing here takes the caret, so there is no second stop inside the surface — open, Tab shuts the list and the press carries on to the next field
240
+ - `Enter` — open the list, or take the answer the arrow keys are resting on
241
+ - `Space` — the same as Enter. The role replaced the button's own activation, so both are written rather than inherited — and a control that opens on one and not the other is a control that feels broken to whoever pressed the wrong one
242
+ - `ArrowDown` — open the list, or move down it
243
+ - `ArrowUp` — open the list at its end, or move up it
244
+ - `Home` — the first answer that can be taken
245
+ - `End` — the last answer that can be taken
246
+ - `a letter` — jump to the first answer beginning with it, and to the next one on pressing it again. A run typed quickly narrows rather than restarting, so "si" reaches Singapore without a search field
247
+ - `Escape` — shut the list, leaving the answer as it was. It also hands the box back the focus, which matters when a pointer has put the caret in the search field: the surface is about to be unmounted, and focus inside it would land on the body
248
+ - The accessible name comes from the label. The label is a <span>, so the association runs from the button through aria-labelledby rather than from a <label> through htmlFor — the thing being named is a button, which htmlFor cannot claim.
249
+ - aria-expanded is present whether the list is open or shut. Not absent when shut: a combobox without it is announced as a control with no state, so "false" is a value to be said rather than a silence to be kept.
250
+ - aria-invalid when the status is an error, and aria-required when the control is required.
251
+ - aria-describedby points at the status message, or at the helper text when no status is showing — whichever one is on screen, and never both, because only one of them is.
252
+ - aria-activedescendant names the row the arrow keys are resting on, and only ever a row that is rendered. It sits on the box, which is the only thing focus rests on here. Nothing when no row is marked: a stale id is worse than none, because a screen reader announces nothing and gives no sign that it looked.
253
+ - aria-busy while a check on the answer is in flight, which is what the pending status means.
254
+ - The search field carries an accessible name taken from the control's own label. A second field inside a control, announced as nothing, is a box a screen reader reaches and cannot say the purpose of — and it is reachable, by pointer, even though the keyboard feeds it from the box.
255
+ - What the status says is legible without its colour. The message carries a glyph whose shape separates an error from a warning, and the words say the same thing the colour does — a visitor who cannot tell red from amber is told by neither.
256
+
257
+ ## Rules
258
+
259
+ - **On a phone a section's actions stack and each fills the width, including when there is only one** — On a phone a page's actions stack, and each one fills the width. Not most of it, and not the width its label happens to need — the whole column.
260
+
261
+ Two side by side is what this replaces. On the narrowest screen each gets half a column minus the gap, which is rarely enough for a real label: the words wrap inside the pills, the two buttons come out different heights, and the pair reads as a broken row rather than as a choice. Stacked, each has the whole width and neither has to shorten its words to fit.
262
+
263
+ A single action fills too, and that is the part worth saying, because it is the one that looks unnecessary. A lone button has the room to sit at its natural width and still should not: a full-width control is the phone's convention for the thing the screen is asking you to do, and a pill hugging its label reads as one option among others that are not there. It also makes the target predictable — the whole width, wherever the thumb lands — which a centred pill does not.
264
+
265
+ Filling is the row's job rather than the button's. A button has no width of its own and is not given one; the row it sits in becomes a column and stretches its children, so nothing about the control changes and the same button is full width here and its own size on a desktop.
266
+
267
+ This is the phone's breakpoint, size.breakpoint.md, and not the wider one that decides whether a heading is centred. Those are different questions and they break at different widths: a heading stops being centred when the measure is the screen, while a button stops being full width much sooner than that — stretched across a tablet it is a long way from its own label, and a label centred in a metre of pill is harder to hit than one in a pill the size of the words.
268
+
269
+ What this is not about is every row of controls. A set of filter chips, a pagination strip, a toolbar, a link sitting after a sentence — none of these is the page asking for something, and stacking them to full width would turn a strip the eye skims into a list it has to read. The test is whether the row is the call to action the section was written for.
270
+ Guidance only — cannot be checked automatically.
271
+ - **Never nest one interactive element inside another** — Nested interactive elements produce ambiguous hit targets and an unreachable inner control for keyboard and screen-reader users. This is why the rule cannot live on any single component — it constrains Button, Link, Input and Switch simultaneously.
272
+ Guidance only — cannot be checked automatically.
273
+ - **A section that paints a ground sets the ink to go with it** — A page sits on color.bg.page, and a section that separates itself from it takes one of three grounds. color.bg.subtle is the light one and needs nothing further — the page's own ink still reads on it. The other two are dark and do not: color.bg.brand-strong takes color.fg.on-brand-strong, and color.bg.brand takes color.fg.on-solid. Both are white, and both are written as the role rather than the white they resolve to. Set one of those backgrounds without its ink and the text inherits whatever the page was already using, which is near-black on a dark band — legible to nobody, and invisible to every check here, because each pair passes contrast on its own and nothing can tell whether a section used both.
274
+
275
+ color.bg.brand carries a second limit that is not about forgetting. Its ink measures 3.39:1, which clears the 3:1 a heading needs and misses the 4.5:1 running copy needs. A coral band may carry a headline and a call to action; a paragraph on one is text the reader has to work through at a ratio the waiver on that role does not cover — the waiver says so itself. A section with copy in it takes color.bg.brand-strong, which is near-black and carries white at full contrast.
276
+
277
+ color.bg.strong is not a section ground. It is the inverted fill for an action that has to outrank what surrounds it, and the components that paint it — Button and ButtonIcon in their inverse form — already set both halves in one rule, which is the pattern a hand-painted section has to copy.
278
+ Guidance only — cannot be checked automatically.
279
+ - **Every gap inside a section names the relationship it expresses, and the same relationship keeps its measure when it turns on its side** — A section's spacing is named by the relationship it expresses, not chosen by size. Every gap in a section has a role token, and reaching for a step off the generic scale because it happens to be the right number is how two sections written by two people stop lining up: the numbers agree today and drift the first time one of them is tuned.
280
+
281
+ The heading group is three steps, not one gap. An eyebrow sits nearer its title than the title sits to its description, and the actions sit further from the description than either — space.heading.eyebrow-title, space.heading.title-description, space.heading.description-actions, in that order. A single `gap` on the group cannot say this; it sets all three the same and the block reads as evenly spaced lines rather than as a mark, a name and a paragraph. The eyebrow has to identify itself for this to work, because a group that opens with a title must not give its description the eyebrow's tighter step.
282
+
283
+ The step between a title and its description follows the size of the title, which is why there are two of it. What a reader sees is not the gap but the gap plus the leading above it, and leading scales with the type: under a display title the leading is most of the space, under a card's title it is half as deep. One value for both makes a card look loose at the size that made a section look right. So space.heading.title-description is the display step and space.heading.title-description-compact is the step at a card's size, and the choice is made by how big the title is rather than by what kind of block it sits in.
284
+
285
+ Every one of those steps is smaller than the gap below the group, and that ordering is what holds the group together as one thing. space.heading.content is the step between a heading group and the content it introduces, and it is the widest measure inside a section: the one gap the eye reads as a change of subject rather than as a continuation.
286
+
287
+ That step is the same whether the content is under the heading or beside it. A split is the same relationship turned on its side — a heading group and the content it introduces — so the space between the two halves is space.heading.content, not a gutter. When the split collapses to one column on a phone the gap becomes vertical again, which is where it started, and nothing has to change for that to be right.
288
+
289
+ space.grid.gutter is between two things of the same kind. Two cards in a row are the same kind; the two halves of a split are not, which is why the gutter is the wrong measure there even when the number would have looked acceptable. The gutter runs on both axes, so a grid reads as an even field rather than as rows with a seam down them.
290
+
291
+ space.inset.card is the card's, not the page's. A row of cards padded differently is a row of different cards, and the fill is the only edge they have. A page composing a row does not get to choose it.
292
+
293
+ Column count is not a breakpoint decision. A row holds as many columns as fit before a column would be narrower than size.grid.column-min, and drops one when they would not. Written as a fixed count that collapses at a breakpoint, a four-up row keeps four columns at every width above the phone and sets its copy two or three words to a line through the whole of the tablet range — and on a narrow desktop, which no breakpoint sits on at all. The threshold is a property of the row rather than of a card: a card fills whatever cell it is given.
294
+
295
+ What this does not cover is the space above and below a section, which is space.section.default and space.section.compact, and the page's own side margin, which is space.inset.page. Those are the section's outside; everything here is its inside.
296
+ Guidance only — cannot be checked automatically.
297
+ - **A section's title is centred over stacked content, starts beside content in columns, and starts on a phone** — Two arrangements, and the title's alignment is decided by which one it is introducing rather than chosen per section.
298
+
299
+ Content stacked under the title — a row of cards, an accordion, a set of steps — takes a centred title. The heading group and the block below it share one axis, so a centred title is symmetric with the thing it names, and the eye drops from the middle of the words to the middle of the set. A title starting at the left over a centred or full-width block reads as belonging to the first column rather than to all of them.
300
+
301
+ Content beside the title — a split, a picture in the other half, anything laid out in columns — takes a title that starts where its content starts. The two share a left edge, and that edge is what says they are one thing read across rather than two stacked. Centring the title there breaks the only alignment the reader has to hold the halves together, and it drifts further from its content the wider the page gets.
302
+
303
+ The heading group is what carries this, not the heading alone. An eyebrow, a title and a description are read as one block and align together; aligning the title without them leaves a centred heading over start-aligned copy, which reads as a mistake rather than as a choice.
304
+
305
+ Centred means all of it, not just the words. A badge, a row of actions, a picture — these are flex children, and a flex child is placed by align-items rather than by text-align, so a block that only sets the text leaves everything that is not text at the start. A hero is the case that shows it: its title and copy centred while its badge and its buttons did not.
306
+
307
+ A capped block centres itself as well as its words. A heading group takes size.heading-group.max, and a cap that is not centred leaves the measure at the start of the column with the words centred inside it — composed, and a long way left of the middle it appears to be in.
308
+
309
+ Both arrangements go to the start on a phone. A centred block reverts below the breakpoint, and the reason is the measure: on a phone the measure is the screen, so a centred title wraps to three or four ragged lines and the eye loses the left edge it was tracking — the same symmetry that reads as composure on a desktop is what makes it hard to scan on a phone. Centring there has to be asked for twice, and a section title is not one of the things that asks: it is centred because there is room for it, and on a phone there is not. Going back to the start means all of it too, and a capped block is the one that hides a leftover: its words go to the start while its measure stays in the middle of the column, which reads as a title still centred over a badge and buttons that are not — the box in the middle and the line inside it at the edge.
310
+
311
+ A hero is a section like any other: its badge, title, copy and actions are one stacked block, so it is centred on a desktop and starts on a phone with everything else.
312
+
313
+ What this is not about is a page whose body is a form or a document. A title over a sign-up form or a guide is not introducing a set of content — it is the first line of the thing itself, and it keeps the alignment the body has, which for running text is the start. The distinction is whether the block below is content the title names or content the title is part of.
314
+ Guidance only — cannot be checked automatically.
315
+ - **Anything a pointer has to hit is at least 24px in both directions** — A control sized by its contents is as big as its contents, and a glyph is chosen for how it reads rather than for how easily it is hit. An icon-only button with no padding is a 16px target — smaller than the pad of a finger, and smaller than the tremor of a hand using a mouse.
316
+
317
+ WCAG 2.2 asks for 24 by 24 CSS pixels at AA. The exceptions are narrower than they look: inline targets inside a sentence are exempt, and so is a small target with 24px of clear space around it — but a clear button sits against the field it empties, and a field is itself a target, so the spacing exemption does not apply to the case that keeps arising.
318
+
319
+ The target and the mark are separate decisions, and conflating them is what produces both faults. Growing the glyph to 24px makes it shout; leaving the button at 16px makes it hard to hit. So the glyph keeps the size that reads correctly beside its text, and the box around it declares a minimum of its own — which is what size.target.min is for.
320
+
321
+ Declared rather than emergent. Padding plus contents does clear 24px in several components today, and it is the weaker statement: it is a size nobody wrote down, so it moves when the type scale or the glyph does, and nothing says it was meant to be a target at all.
322
+ Guidance only — cannot be checked automatically.
323
+
324
+ ## Anti-examples
325
+
326
+ ❌ Select for: The set is a handful and worth comparing side by side
327
+ Two to four alternatives that exclude one another are decided by weighing them against each other, and a reader cannot weigh what is behind a closed box. A shut control makes the reader open it to find out what the choices even are, which is a press spent on nothing
328
+ → use `SegmentedControl` instead.
329
+
330
+ ❌ Select for: The choices are destinations rather than answers
331
+ A menu goes somewhere and a field holds something. Drawn as a field, a set of links reads as a question the visitor is being asked, and they will look for the button that submits it
332
+ → use `DropdownMenu` instead.
333
+
334
+ ❌ Select for: The reader can pick more than one
335
+ Nothing here does this, which is the useful thing to know rather than a gap to work around. This control shows one answer in a box sized for one, and a page needing several narrowings at once wants a row of RemovableChips above its results — each coming off on its own without clearing the rest
336
+ → nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
337
+
338
+ ❌ Select for: The answer is not on the list, and typing one should stand
339
+ Nothing here does this either. The search field inside this control is a way through the list and never an answer: nothing is accepted that is not on it. Product has a Combobox for the other case and marketing has none, so a page needing it is a page that should ask for one
340
+ → nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
341
+
342
+ ❌ required=true + optional=true
343
+ A control is one or the other, and marking it both says nothing
344
+
345
+ ❌ status=error + statusMessage missing or empty
346
+ An error with no explanation leaves the visitor stuck, and a visitor stuck on a marketing form leaves the page rather than the field
347
+
348
+ ❌ status=warning + statusMessage missing or empty
349
+ A warning with no explanation is a control the reader cannot act on
350
+
351
+ ❌ status=pending + statusMessage missing or empty
352
+ A wait with nothing said is a control that has stopped responding. There is nowhere inside the box for a mark to go — it holds the answer and the chevron — so the row beneath is the only thing that can carry it
353
+
354
+ ❌ fixed=true + state=hover
355
+ A box that does not open has nothing to offer a pointer, so there is no ring for it to take. A styling-matrix exemption rather than an API constraint: fixed is a real value and hover is a real state, and what does not exist is a treatment for the two together
356
+
357
+ ❌ searchable=true + emptyLabel missing or empty
358
+ A list that can be narrowed to nothing has to say when it has been, or the surface empties with nothing to explain it
359
+
360
+ ## Example
361
+
362
+ ```tsx
363
+ import { Select, Option } from '@deriv-com/dds-marketing'
364
+
365
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" helperText="This only changes which prices we show you" defaultValue="sg">
366
+ <Option value="sg">Singapore</Option>
367
+ <Option value="ie">Ireland</Option>
368
+ <Option value="de">Germany</Option>
369
+ <Option value="za">South Africa</Option>
370
+ </Select>
371
+ ```
372
+
373
+ ```tsx
374
+ import { useState } from 'react'
375
+ import { Select, Option } from '@deriv-com/dds-marketing'
376
+
377
+ // Controlled: Select reports the value, not the event.
378
+ const [value, setValue] = useState('')
379
+ <Select label="Country" placeholder="Select a country" helperText="This only changes which prices we show you" value={value} onChange={setValue} onOpenChange={(open) => { /* your handler */ }}>
380
+ <Option value="sg">Singapore</Option>
381
+ <Option value="ie">Ireland</Option>
382
+ <Option value="de">Germany</Option>
383
+ <Option value="za">South Africa</Option>
384
+ </Select>
385
+ ```
386
+
387
+ ## In use
388
+
389
+ Most rows below hold the same set, written once here:
390
+
391
+ ```tsx
392
+ import { Option } from '@deriv-com/dds-marketing'
393
+
394
+ const options = (
395
+ <>
396
+ <Option value="sg">Singapore</Option>
397
+ <Option value="ie">Ireland</Option>
398
+ <Option value="de">Germany</Option>
399
+ <Option value="za">South Africa</Option>
400
+ </>
401
+ )
402
+ ```
403
+
404
+ ### The two jobs it does
405
+
406
+ It collects an answer a form submits, and it narrows what is already on the page. Nothing in the control changes between them, which is why they are one component and not two.
407
+
408
+ ```tsx
409
+ import { Option, Select } from '@deriv-com/dds-marketing'
410
+
411
+ // A form answer — sent when they press send
412
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" helperText="This only changes which prices we show you">{options}</Select>
413
+
414
+ // A narrowing — reshapes the page at once
415
+ <Select onChange={(value) => { /* your handler */ }} size="sm" label="Sort" placeholder="Newest first" defaultValue="newest">
416
+ <Option value="newest">Newest first</Option>
417
+ <Option value="oldest">Oldest first</Option>
418
+ <Option value="read">Most read</Option>
419
+ </Select>
420
+ ```
421
+
422
+ ### Answered, and not yet
423
+
424
+ Shut is how a visitor meets it, and what it shows then is the answer they gave. What separates a given answer from a waiting placeholder is the ink, not the weight.
425
+
426
+ ```tsx
427
+ import { Select } from '@deriv-com/dds-marketing'
428
+
429
+ // Nothing taken — an instruction, not an example
430
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country">{options}</Select>
431
+
432
+ // Answered — the words, never the value
433
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" defaultValue="ie">{options}</Select>
434
+ ```
435
+
436
+ ### Three steps, and a form that agrees
437
+
438
+ The size chooses the type, the inset and the height — the same three things it chooses on a TextInput, so a contact form's country field and its email field are the same height.
439
+
440
+ ```tsx
441
+ import { Option, Select } from '@deriv-com/dds-marketing'
442
+
443
+ // sm — a filter row above an index, desktop only
444
+ <Select onChange={(value) => { /* your handler */ }} size="sm" label="Sort" placeholder="Newest first">
445
+ <Option value="newest">Newest first</Option>
446
+ <Option value="oldest">Oldest first</Option>
447
+ <Option value="read">Most read</Option>
448
+ </Select>
449
+
450
+ // md — the default, and what a marketing form wants
451
+ <Select onChange={(value) => { /* your handler */ }} size="md" label="Country" placeholder="Select a country">{options}</Select>
452
+
453
+ // lg — a hero, or a form that is the point of the page
454
+ <Select onChange={(value) => { /* your handler */ }} size="lg" label="Country" placeholder="Select a country">{options}</Select>
455
+ ```
456
+
457
+ ### What a check came back with
458
+
459
+ Every status arrives after the visitor presses send, because a landing page has nothing to check against until then. Each one obliges a message: the colour is not the part a colour-blind reader gets.
460
+
461
+ ```tsx
462
+ import { Select } from '@deriv-com/dds-marketing'
463
+
464
+ // error — and what to do about it
465
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" status="error" statusMessage="Choose the country you are getting in touch from">{options}</Select>
466
+
467
+ // warning — accepted, and likely not what they meant
468
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" defaultValue="za" status="warning" statusMessage="We do not publish prices for South Africa yet">{options}</Select>
469
+
470
+ // pending — a wait is not a verdict
471
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" defaultValue="de" status="pending" statusMessage="Checking what we can offer in Germany">{options}</Select>
472
+
473
+ // success — only when something was checked
474
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" defaultValue="ie" status="success" statusMessage="Prices below are in euro">{options}</Select>
475
+ ```
476
+
477
+ ### A long set, and a way through it
478
+
479
+ A field opens at the top of the list and narrows it to what the visitor types. The typing is a way through the answers and never an answer: nothing is accepted that is not on the list.
480
+
481
+ ```tsx
482
+ import { Select } from '@deriv-com/dds-marketing'
483
+
484
+ // searchable — with its empty-list sentence
485
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" searchable emptyLabel="No countries match">{options}</Select>
486
+ ```
487
+
488
+ ### Marked, explained, and settled
489
+
490
+ The label row carries what the visitor needs before they open the list. Required or optional, never both — and an explanation the label has no room for sits beside it rather than under it.
491
+
492
+ ```tsx
493
+ import { Select } from '@deriv-com/dds-marketing'
494
+
495
+ // required — said before they reach the end of the form
496
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" required>{options}</Select>
497
+
498
+ // asterisk — only where a legend says what it means
499
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" required requiredMark="asterisk">{options}</Select>
500
+
501
+ // optional — the shape most marketing forms take
502
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" optional>{options}</Select>
503
+
504
+ // an explanation, on hover and on focus
505
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" labelTooltip="We ask so we can show you the right prices and the right legal notices">{options}</Select>
506
+
507
+ // fixed — settled, and still worth reading
508
+ <Select onChange={(value) => { /* your handler */ }} label="Country" placeholder="Select a country" fixed defaultValue="sg">{options}</Select>
509
+ ```