@ui-sdk/web 0.0.0-stage → 0.1.0-beta.1

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 (467) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +10 -2
  3. package/browser/web/accordion.js +1 -0
  4. package/browser/web/alert-dialog.js +1 -0
  5. package/browser/web/autocomplete.js +1 -0
  6. package/browser/web/avatar.js +1 -0
  7. package/browser/web/button.js +1 -0
  8. package/browser/web/calendar.js +1 -0
  9. package/browser/web/carousel.js +1 -0
  10. package/browser/web/checkbox.js +1 -0
  11. package/browser/web/chunks/0eRGibL6.js +1 -0
  12. package/browser/web/chunks/2bIEUO6_.js +1 -0
  13. package/browser/web/chunks/5A9w2ULz.js +1 -0
  14. package/browser/web/chunks/5RSyydjV.js +1 -0
  15. package/browser/web/chunks/9pWTy2wl.js +1 -0
  16. package/browser/web/chunks/B0f2j6zz.js +1 -0
  17. package/browser/web/chunks/B1rux6br.js +1 -0
  18. package/browser/web/chunks/B3-APaNf.js +1 -0
  19. package/browser/web/chunks/B7EgSgjQ.js +1 -0
  20. package/browser/web/chunks/B8QcOzJU.js +1 -0
  21. package/browser/web/chunks/BFueEkwm.js +3 -0
  22. package/browser/web/chunks/BJj3oS29.js +1 -0
  23. package/browser/web/chunks/BNSvTCpr.js +1 -0
  24. package/browser/web/chunks/BPD0kAZB.js +1 -0
  25. package/browser/web/chunks/BQeduZqT.js +1 -0
  26. package/browser/web/chunks/B_CVFyiz.js +1 -0
  27. package/browser/web/chunks/B_ns1YHO.js +1 -0
  28. package/browser/web/chunks/BcwkVTsR.js +1 -0
  29. package/browser/web/chunks/BeaQ6TYM.js +1 -0
  30. package/browser/web/chunks/BgBB013u.js +1 -0
  31. package/browser/web/chunks/BgsKhHDm.js +1 -0
  32. package/browser/web/chunks/BjMcbuhi.js +9 -0
  33. package/browser/web/chunks/Bjiy_F2N.js +1 -0
  34. package/browser/web/chunks/BqScCLwv.js +1 -0
  35. package/browser/web/chunks/BqX3Utqx.js +1 -0
  36. package/browser/web/chunks/BtVkQf3z.js +1 -0
  37. package/browser/web/chunks/By30h-7B.js +1 -0
  38. package/browser/web/chunks/C1zqYpy2.js +1 -0
  39. package/browser/web/chunks/C436juFf.js +1 -0
  40. package/browser/web/chunks/C4_bULs1.js +1 -0
  41. package/browser/web/chunks/C4omqJEz.js +1 -0
  42. package/browser/web/chunks/C7tt0T3n.js +1 -0
  43. package/browser/web/chunks/C8w7s5dg.js +1 -0
  44. package/browser/web/chunks/CElY4erO.js +1 -0
  45. package/browser/web/chunks/CFODo-m2.js +1 -0
  46. package/browser/web/chunks/CL4wjam9.js +1 -0
  47. package/browser/web/chunks/CMg-8UVf.js +1 -0
  48. package/browser/web/chunks/COWKfakj.js +1 -0
  49. package/browser/web/chunks/CQBU0qZ4.js +1 -0
  50. package/browser/web/chunks/CV6uABgc.js +1 -0
  51. package/browser/web/chunks/C_SWFpWQ.js +1 -0
  52. package/browser/web/chunks/C_Uanbrl.js +1 -0
  53. package/browser/web/chunks/Ce_CSanC.js +1 -0
  54. package/browser/web/chunks/Cg-ZmRhS.js +1 -0
  55. package/browser/web/chunks/Cgf2wPI_.js +1 -0
  56. package/browser/web/chunks/Cuep_3Vf.js +1 -0
  57. package/browser/web/chunks/D02PaHn6.js +1 -0
  58. package/browser/web/chunks/D5LiaI5R.js +1 -0
  59. package/browser/web/chunks/D9UgVYvF.js +1 -0
  60. package/browser/web/chunks/DC08tnkE.js +2 -0
  61. package/browser/web/chunks/DG8YGSvu.js +1 -0
  62. package/browser/web/chunks/DIQd0FYD.js +1 -0
  63. package/browser/web/chunks/DMLqacE8.js +1 -0
  64. package/browser/web/chunks/DSUI3yI-.js +1 -0
  65. package/browser/web/chunks/DT3Hb76X.js +1 -0
  66. package/browser/web/chunks/DY75g3-W.js +1 -0
  67. package/browser/web/chunks/DZpNQKZ9.js +1 -0
  68. package/browser/web/chunks/Db-W1wrC.js +1 -0
  69. package/browser/web/chunks/Dc1xK3Ii.js +1 -0
  70. package/browser/web/chunks/DdF6awFs.js +1 -0
  71. package/browser/web/chunks/DdaCLml8.js +1 -0
  72. package/browser/web/chunks/Dh8MLjQO.js +1 -0
  73. package/browser/web/chunks/DiuslJRy.js +1 -0
  74. package/browser/web/chunks/DjRcw3Y0.js +1 -0
  75. package/browser/web/chunks/Djdv-16J.js +1 -0
  76. package/browser/web/chunks/DnFXe_lF.js +1 -0
  77. package/browser/web/chunks/DneGv1oC.js +1 -0
  78. package/browser/web/chunks/DsVxP-p-.js +1 -0
  79. package/browser/web/chunks/DwDilCo2.js +1 -0
  80. package/browser/web/chunks/DwV48AXv.js +1 -0
  81. package/browser/web/chunks/F37aF4-L.js +1 -0
  82. package/browser/web/chunks/LyB6XIbN.js +1 -0
  83. package/browser/web/chunks/NKnbYGjC.js +1 -0
  84. package/browser/web/chunks/Vk-rVi16.js +1 -0
  85. package/browser/web/chunks/XsM0J1Ex.js +1 -0
  86. package/browser/web/chunks/asSN9iEp.js +1 -0
  87. package/browser/web/chunks/c-AjHfdF.js +1 -0
  88. package/browser/web/chunks/dR-12TPY.js +1 -0
  89. package/browser/web/chunks/hR4xM0EC.js +1 -0
  90. package/browser/web/chunks/hqOaBxAg.js +1 -0
  91. package/browser/web/chunks/kMKqqeG4.js +1 -0
  92. package/browser/web/chunks/kXboBcfi.js +1 -0
  93. package/browser/web/chunks/l4aQIg22.js +1 -0
  94. package/browser/web/chunks/tJC0JSU4.js +1 -0
  95. package/browser/web/chunks/wHdS_QYM.js +1 -0
  96. package/browser/web/chunks/yv8dTvNI.js +1 -0
  97. package/browser/web/chunks/yw9M3nfi.js +1 -0
  98. package/browser/web/collapsible.js +1 -0
  99. package/browser/web/color-picker.js +1 -0
  100. package/browser/web/combobox.js +2 -0
  101. package/browser/web/command.js +1 -0
  102. package/browser/web/core.js +5 -0
  103. package/browser/web/date-input.js +1 -0
  104. package/browser/web/date-picker.js +1 -0
  105. package/browser/web/dialog.js +1 -0
  106. package/browser/web/drawer.js +1 -0
  107. package/browser/web/field.js +1 -0
  108. package/browser/web/file-input.js +1 -0
  109. package/browser/web/hover-card.js +1 -0
  110. package/browser/web/image-cropper.js +1 -0
  111. package/browser/web/input.js +1 -0
  112. package/browser/web/label.js +1 -0
  113. package/browser/web/listbox.js +1 -0
  114. package/browser/web/menu.js +1 -0
  115. package/browser/web/menubar.js +1 -0
  116. package/browser/web/meter.js +1 -0
  117. package/browser/web/navigation-menu.js +1 -0
  118. package/browser/web/number-input.js +1 -0
  119. package/browser/web/otp-input.js +2 -0
  120. package/browser/web/overlays.js +1 -0
  121. package/browser/web/pagination.js +1 -0
  122. package/browser/web/password-input.js +1 -0
  123. package/browser/web/popover.js +1 -0
  124. package/browser/web/preferences.js +1 -0
  125. package/browser/web/progress.js +1 -0
  126. package/browser/web/radio.js +1 -0
  127. package/browser/web/rating.js +1 -0
  128. package/browser/web/resizable.js +1 -0
  129. package/browser/web/scroll-area.js +1 -0
  130. package/browser/web/segmented-control.js +1 -0
  131. package/browser/web/select.js +1 -0
  132. package/browser/web/separator.js +1 -0
  133. package/browser/web/slider.js +1 -0
  134. package/browser/web/switch.js +1 -0
  135. package/browser/web/tabs.js +1 -0
  136. package/browser/web/textarea.js +1 -0
  137. package/browser/web/time-input.js +1 -0
  138. package/browser/web/timeline.js +1 -0
  139. package/browser/web/toast.js +1 -0
  140. package/browser/web/toggle.js +1 -0
  141. package/browser/web/token-input.js +8 -0
  142. package/browser/web/toolbar.js +1 -0
  143. package/browser/web/tooltip.js +1 -0
  144. package/browser/web/tree.js +1 -0
  145. package/browser/web/trigger-menu.js +4 -0
  146. package/browser/web/waterfall.js +1 -0
  147. package/browser/web.css +3378 -0
  148. package/browser/web.js +3 -0
  149. package/custom-elements.json +32315 -0
  150. package/dist/accordion.d.ts +2 -0
  151. package/dist/accordion.js +57 -0
  152. package/dist/action.d.ts +16 -0
  153. package/dist/action.js +39 -0
  154. package/dist/agent.d.ts +2 -0
  155. package/dist/agent.js +7 -0
  156. package/dist/autocomplete.d.ts +2 -0
  157. package/dist/autocomplete.js +120 -0
  158. package/dist/autoload.d.ts +18 -0
  159. package/dist/autoload.js +63 -0
  160. package/dist/avatar.d.ts +2 -0
  161. package/dist/avatar.js +27 -0
  162. package/dist/browser-core.d.ts +2 -0
  163. package/dist/browser-core.js +8 -0
  164. package/dist/button.d.ts +2 -0
  165. package/dist/button.js +35 -0
  166. package/dist/calendar.d.ts +23 -0
  167. package/dist/calendar.js +429 -0
  168. package/dist/carousel.d.ts +2 -0
  169. package/dist/carousel.js +54 -0
  170. package/dist/checkbox.d.ts +4 -0
  171. package/dist/checkbox.js +75 -0
  172. package/dist/collapsible.d.ts +2 -0
  173. package/dist/collapsible.js +28 -0
  174. package/dist/color-picker.d.ts +2 -0
  175. package/dist/color-picker.js +64 -0
  176. package/dist/combobox.d.ts +2 -0
  177. package/dist/combobox.js +334 -0
  178. package/dist/command.d.ts +2 -0
  179. package/dist/command.js +122 -0
  180. package/dist/date-input.d.ts +3 -0
  181. package/dist/date-input.js +87 -0
  182. package/dist/date-picker.d.ts +2 -0
  183. package/dist/date-picker.js +174 -0
  184. package/dist/default-text.d.ts +3 -0
  185. package/dist/default-text.js +24 -0
  186. package/dist/define-element.d.ts +404 -0
  187. package/dist/define-element.js +1489 -0
  188. package/dist/dialog.d.ts +3 -0
  189. package/dist/dialog.js +94 -0
  190. package/dist/drawer.d.ts +2 -0
  191. package/dist/drawer.js +96 -0
  192. package/dist/entries/accordion.d.ts +3 -0
  193. package/dist/entries/accordion.js +7 -0
  194. package/dist/entries/alert-dialog.d.ts +3 -0
  195. package/dist/entries/alert-dialog.js +13 -0
  196. package/dist/entries/autocomplete.d.ts +3 -0
  197. package/dist/entries/autocomplete.js +7 -0
  198. package/dist/entries/avatar.d.ts +2 -0
  199. package/dist/entries/avatar.js +3 -0
  200. package/dist/entries/button.d.ts +2 -0
  201. package/dist/entries/button.js +3 -0
  202. package/dist/entries/calendar.d.ts +3 -0
  203. package/dist/entries/calendar.js +7 -0
  204. package/dist/entries/carousel.d.ts +3 -0
  205. package/dist/entries/carousel.js +7 -0
  206. package/dist/entries/checkbox.d.ts +3 -0
  207. package/dist/entries/checkbox.js +15 -0
  208. package/dist/entries/collapsible.d.ts +3 -0
  209. package/dist/entries/collapsible.js +7 -0
  210. package/dist/entries/color-picker.d.ts +3 -0
  211. package/dist/entries/color-picker.js +7 -0
  212. package/dist/entries/combobox.d.ts +3 -0
  213. package/dist/entries/combobox.js +7 -0
  214. package/dist/entries/command.d.ts +3 -0
  215. package/dist/entries/command.js +7 -0
  216. package/dist/entries/date-input.d.ts +3 -0
  217. package/dist/entries/date-input.js +7 -0
  218. package/dist/entries/date-picker.d.ts +3 -0
  219. package/dist/entries/date-picker.js +7 -0
  220. package/dist/entries/dialog.d.ts +3 -0
  221. package/dist/entries/dialog.js +7 -0
  222. package/dist/entries/drawer.d.ts +3 -0
  223. package/dist/entries/drawer.js +8 -0
  224. package/dist/entries/field.d.ts +2 -0
  225. package/dist/entries/field.js +3 -0
  226. package/dist/entries/file-input.d.ts +3 -0
  227. package/dist/entries/file-input.js +13 -0
  228. package/dist/entries/hover-card.d.ts +3 -0
  229. package/dist/entries/hover-card.js +7 -0
  230. package/dist/entries/image-cropper.d.ts +3 -0
  231. package/dist/entries/image-cropper.js +7 -0
  232. package/dist/entries/input.d.ts +3 -0
  233. package/dist/entries/input.js +8 -0
  234. package/dist/entries/label.d.ts +2 -0
  235. package/dist/entries/label.js +3 -0
  236. package/dist/entries/listbox.d.ts +3 -0
  237. package/dist/entries/listbox.js +7 -0
  238. package/dist/entries/menu.d.ts +3 -0
  239. package/dist/entries/menu.js +7 -0
  240. package/dist/entries/menubar.d.ts +3 -0
  241. package/dist/entries/menubar.js +7 -0
  242. package/dist/entries/meter.d.ts +2 -0
  243. package/dist/entries/meter.js +3 -0
  244. package/dist/entries/navigation-menu.d.ts +3 -0
  245. package/dist/entries/navigation-menu.js +7 -0
  246. package/dist/entries/number-input.d.ts +3 -0
  247. package/dist/entries/number-input.js +7 -0
  248. package/dist/entries/otp-input.d.ts +3 -0
  249. package/dist/entries/otp-input.js +7 -0
  250. package/dist/entries/overlays.d.ts +2 -0
  251. package/dist/entries/overlays.js +3 -0
  252. package/dist/entries/pagination.d.ts +3 -0
  253. package/dist/entries/pagination.js +11 -0
  254. package/dist/entries/password-input.d.ts +3 -0
  255. package/dist/entries/password-input.js +7 -0
  256. package/dist/entries/popover.d.ts +3 -0
  257. package/dist/entries/popover.js +7 -0
  258. package/dist/entries/preferences.d.ts +3 -0
  259. package/dist/entries/preferences.js +13 -0
  260. package/dist/entries/progress.d.ts +2 -0
  261. package/dist/entries/progress.js +3 -0
  262. package/dist/entries/radio.d.ts +3 -0
  263. package/dist/entries/radio.js +7 -0
  264. package/dist/entries/rating.d.ts +3 -0
  265. package/dist/entries/rating.js +8 -0
  266. package/dist/entries/resizable.d.ts +3 -0
  267. package/dist/entries/resizable.js +11 -0
  268. package/dist/entries/scroll-area.d.ts +3 -0
  269. package/dist/entries/scroll-area.js +7 -0
  270. package/dist/entries/segmented-control.d.ts +3 -0
  271. package/dist/entries/segmented-control.js +7 -0
  272. package/dist/entries/select.d.ts +3 -0
  273. package/dist/entries/select.js +7 -0
  274. package/dist/entries/separator.d.ts +2 -0
  275. package/dist/entries/separator.js +3 -0
  276. package/dist/entries/slider.d.ts +3 -0
  277. package/dist/entries/slider.js +7 -0
  278. package/dist/entries/switch.d.ts +3 -0
  279. package/dist/entries/switch.js +7 -0
  280. package/dist/entries/tabs.d.ts +3 -0
  281. package/dist/entries/tabs.js +7 -0
  282. package/dist/entries/textarea.d.ts +3 -0
  283. package/dist/entries/textarea.js +7 -0
  284. package/dist/entries/time-input.d.ts +3 -0
  285. package/dist/entries/time-input.js +7 -0
  286. package/dist/entries/timeline.d.ts +3 -0
  287. package/dist/entries/timeline.js +7 -0
  288. package/dist/entries/toast.d.ts +2 -0
  289. package/dist/entries/toast.js +3 -0
  290. package/dist/entries/toggle.d.ts +3 -0
  291. package/dist/entries/toggle.js +12 -0
  292. package/dist/entries/token-input.d.ts +3 -0
  293. package/dist/entries/token-input.js +17 -0
  294. package/dist/entries/toolbar.d.ts +3 -0
  295. package/dist/entries/toolbar.js +7 -0
  296. package/dist/entries/tooltip.d.ts +3 -0
  297. package/dist/entries/tooltip.js +7 -0
  298. package/dist/entries/tree.d.ts +3 -0
  299. package/dist/entries/tree.js +17 -0
  300. package/dist/entries/trigger-menu.d.ts +3 -0
  301. package/dist/entries/trigger-menu.js +11 -0
  302. package/dist/entries/waterfall.d.ts +3 -0
  303. package/dist/entries/waterfall.js +11 -0
  304. package/dist/events.d.ts +1658 -0
  305. package/dist/events.js +0 -0
  306. package/dist/field.d.ts +2 -0
  307. package/dist/field.js +101 -0
  308. package/dist/file-input.d.ts +2 -0
  309. package/dist/file-input.js +140 -0
  310. package/dist/forward-attributes.d.ts +2 -0
  311. package/dist/forward-attributes.js +22 -0
  312. package/dist/history.d.ts +2 -0
  313. package/dist/history.js +11 -0
  314. package/dist/hover-card.d.ts +2 -0
  315. package/dist/hover-card.js +31 -0
  316. package/dist/image-cropper.d.ts +2 -0
  317. package/dist/image-cropper.js +66 -0
  318. package/dist/index.d.ts +66 -0
  319. package/dist/index.js +269 -0
  320. package/dist/input.d.ts +3 -0
  321. package/dist/input.js +69 -0
  322. package/dist/label.d.ts +2 -0
  323. package/dist/label.js +11 -0
  324. package/dist/list.d.ts +40 -0
  325. package/dist/list.js +192 -0
  326. package/dist/listbox.d.ts +2 -0
  327. package/dist/listbox.js +84 -0
  328. package/dist/menu.d.ts +4 -0
  329. package/dist/menu.js +295 -0
  330. package/dist/menubar.d.ts +4 -0
  331. package/dist/menubar.js +30 -0
  332. package/dist/meter.d.ts +2 -0
  333. package/dist/meter.js +22 -0
  334. package/dist/navigation-menu.d.ts +2 -0
  335. package/dist/navigation-menu.js +114 -0
  336. package/dist/number-input.d.ts +2 -0
  337. package/dist/number-input.js +73 -0
  338. package/dist/observe.d.ts +2 -0
  339. package/dist/observe.js +7 -0
  340. package/dist/otp-input.d.ts +2 -0
  341. package/dist/otp-input.js +72 -0
  342. package/dist/overlays.d.ts +13 -0
  343. package/dist/overlays.js +156 -0
  344. package/dist/pagination.d.ts +2 -0
  345. package/dist/pagination.js +127 -0
  346. package/dist/password-input.d.ts +2 -0
  347. package/dist/password-input.js +57 -0
  348. package/dist/popover.d.ts +2 -0
  349. package/dist/popover.js +64 -0
  350. package/dist/popup.d.ts +40 -0
  351. package/dist/popup.js +112 -0
  352. package/dist/preferences.d.ts +2 -0
  353. package/dist/preferences.js +56 -0
  354. package/dist/progress.d.ts +2 -0
  355. package/dist/progress.js +22 -0
  356. package/dist/radio.d.ts +2 -0
  357. package/dist/radio.js +33 -0
  358. package/dist/rating.d.ts +2 -0
  359. package/dist/rating.js +64 -0
  360. package/dist/resizable.d.ts +2 -0
  361. package/dist/resizable.js +42 -0
  362. package/dist/scroll-area.d.ts +2 -0
  363. package/dist/scroll-area.js +45 -0
  364. package/dist/segmented-control.d.ts +2 -0
  365. package/dist/segmented-control.js +28 -0
  366. package/dist/select.d.ts +2 -0
  367. package/dist/select.js +239 -0
  368. package/dist/separator.d.ts +2 -0
  369. package/dist/separator.js +11 -0
  370. package/dist/slider.d.ts +2 -0
  371. package/dist/slider.js +77 -0
  372. package/dist/tabs.d.ts +2 -0
  373. package/dist/tabs.js +37 -0
  374. package/dist/timeline.d.ts +2 -0
  375. package/dist/timeline.js +27 -0
  376. package/dist/toast.d.ts +20 -0
  377. package/dist/toast.js +177 -0
  378. package/dist/toggle.d.ts +3 -0
  379. package/dist/toggle.js +64 -0
  380. package/dist/token-input.d.ts +2 -0
  381. package/dist/token-input.js +103 -0
  382. package/dist/toolbar.d.ts +2 -0
  383. package/dist/toolbar.js +36 -0
  384. package/dist/tooltip.d.ts +2 -0
  385. package/dist/tooltip.js +35 -0
  386. package/dist/tree.d.ts +2 -0
  387. package/dist/tree.js +147 -0
  388. package/dist/trigger-menu.d.ts +2 -0
  389. package/dist/trigger-menu.js +133 -0
  390. package/dist/waterfall.d.ts +2 -0
  391. package/dist/waterfall.js +140 -0
  392. package/docs/README.md +89 -0
  393. package/docs/agents.md +1523 -0
  394. package/docs/components/accordion.md +1401 -0
  395. package/docs/components/alert-dialog.md +788 -0
  396. package/docs/components/autocomplete.md +1692 -0
  397. package/docs/components/avatar.md +261 -0
  398. package/docs/components/button.md +441 -0
  399. package/docs/components/calendar.md +1536 -0
  400. package/docs/components/carousel.md +1055 -0
  401. package/docs/components/checkbox.md +1045 -0
  402. package/docs/components/collapsible.md +535 -0
  403. package/docs/components/color-picker.md +651 -0
  404. package/docs/components/combobox.md +3274 -0
  405. package/docs/components/command.md +1431 -0
  406. package/docs/components/date-input.md +563 -0
  407. package/docs/components/date-picker.md +1136 -0
  408. package/docs/components/dialog.md +1360 -0
  409. package/docs/components/drawer.md +1201 -0
  410. package/docs/components/field.md +519 -0
  411. package/docs/components/file-input.md +617 -0
  412. package/docs/components/hover-card.md +486 -0
  413. package/docs/components/image-cropper.md +489 -0
  414. package/docs/components/input.md +327 -0
  415. package/docs/components/label.md +208 -0
  416. package/docs/components/listbox.md +1015 -0
  417. package/docs/components/menu.md +1212 -0
  418. package/docs/components/menubar.md +460 -0
  419. package/docs/components/meter.md +298 -0
  420. package/docs/components/navigation-menu.md +1573 -0
  421. package/docs/components/number-input.md +1087 -0
  422. package/docs/components/otp-input.md +558 -0
  423. package/docs/components/pagination.md +639 -0
  424. package/docs/components/password-input.md +649 -0
  425. package/docs/components/popover.md +1433 -0
  426. package/docs/components/preferences.md +243 -0
  427. package/docs/components/progress.md +406 -0
  428. package/docs/components/radio.md +855 -0
  429. package/docs/components/rating.md +431 -0
  430. package/docs/components/resizable.md +866 -0
  431. package/docs/components/scroll-area.md +898 -0
  432. package/docs/components/segmented-control.md +421 -0
  433. package/docs/components/select.md +1957 -0
  434. package/docs/components/separator.md +238 -0
  435. package/docs/components/slider.md +1018 -0
  436. package/docs/components/switch.md +583 -0
  437. package/docs/components/tabs.md +948 -0
  438. package/docs/components/textarea.md +331 -0
  439. package/docs/components/time-input.md +235 -0
  440. package/docs/components/timeline.md +622 -0
  441. package/docs/components/toast.md +1223 -0
  442. package/docs/components/toggle.md +522 -0
  443. package/docs/components/token-input.md +854 -0
  444. package/docs/components/toolbar.md +815 -0
  445. package/docs/components/tooltip.md +860 -0
  446. package/docs/components/tree.md +1243 -0
  447. package/docs/components/trigger-menu.md +1110 -0
  448. package/docs/components/waterfall.md +709 -0
  449. package/docs/controllers.md +66 -0
  450. package/docs/core.md +8027 -0
  451. package/docs/custom-parts.md +91 -0
  452. package/docs/first-component.md +88 -0
  453. package/docs/forms.md +125 -0
  454. package/docs/installation.md +141 -0
  455. package/docs/introduction.md +32 -0
  456. package/docs/lists-and-menus.md +166 -0
  457. package/docs/llms.txt +1566 -0
  458. package/docs/parts-and-composition.md +57 -0
  459. package/docs/popups.md +92 -0
  460. package/docs/rendering.md +71 -0
  461. package/docs/server-rendering.md +118 -0
  462. package/docs/state-and-events.md +134 -0
  463. package/docs/styling-and-animation.md +104 -0
  464. package/docs/utilities/async-options.md +332 -0
  465. package/docs/utilities/shortcuts.md +184 -0
  466. package/html-custom-data.json +14792 -0
  467. package/package.json +302 -3
@@ -0,0 +1,1692 @@
1
+ # Autocomplete
2
+
3
+ Suggest text while someone types, without limiting what they can enter.
4
+
5
+ Use Autocomplete for a text field with helpful suggestions. Choosing one fills in the field, but any text is a valid value. Use [Combobox](./combobox.md) when the value should be a selected option instead.
6
+
7
+ ```ts title="demo.ts"
8
+ import "@ui-sdk/web/autocomplete"
9
+
10
+ const fruits = [
11
+ "Apple",
12
+ "Apricot",
13
+ "Avocado",
14
+ "Banana",
15
+ "Blackberry",
16
+ "Blueberry",
17
+ "Cherry",
18
+ "Grape",
19
+ "Lemon",
20
+ "Mango",
21
+ "Orange",
22
+ "Peach",
23
+ "Pear",
24
+ "Pineapple",
25
+ "Strawberry",
26
+ ]
27
+
28
+ function mount(root: HTMLElement) {
29
+ root.innerHTML = `
30
+ <ui-autocomplete>
31
+ <div data-slot="stack">
32
+ <ui-autocomplete-label>Favorite fruit</ui-autocomplete-label>
33
+ <ui-autocomplete-input>
34
+ <input placeholder="e.g. Mango" />
35
+ </ui-autocomplete-input>
36
+ </div>
37
+ <ui-autocomplete-content hidden>
38
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
39
+ <ui-autocomplete-list>
40
+ ${fruits
41
+ .map(
42
+ (fruit) => `
43
+ <ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>
44
+ `
45
+ )
46
+ .join("")}
47
+ </ui-autocomplete-list>
48
+ </ui-autocomplete-content>
49
+ </ui-autocomplete>
50
+ `
51
+ }
52
+
53
+ export { mount }
54
+ ```
55
+
56
+ Type “man”, press Down Arrow, then Enter to fill in Mango. You can also leave text that is not in the list.
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ npm install @ui-sdk/web @ui-sdk/core
62
+ ```
63
+
64
+ Import the element definitions once in your application:
65
+
66
+ ```ts
67
+ import "@ui-sdk/web/autocomplete"
68
+ ```
69
+
70
+ ## Composition
71
+
72
+ Use the following composition to build a `ui-autocomplete`:
73
+
74
+ ```text
75
+ ui-autocomplete
76
+ ├── ui-autocomplete-label
77
+ ├── ui-autocomplete-input
78
+ │ └── input
79
+ └── ui-autocomplete-content
80
+ ├── ui-autocomplete-empty
81
+ └── ui-autocomplete-list
82
+ ├── ui-autocomplete-item
83
+ └── ui-autocomplete-item
84
+ ```
85
+
86
+ Name the input, then put suggestions in a list inside the popup. `ui-autocomplete-input` wraps a native input. Each suggestion needs a unique value.
87
+
88
+ ## Usage
89
+
90
+ Import the parts and put them together:
91
+
92
+ ```html
93
+ <script type="module">
94
+ import "@ui-sdk/web/autocomplete"
95
+ </script>
96
+
97
+ <ui-autocomplete>
98
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
99
+ <ui-autocomplete-input
100
+ ><input placeholder="Type a fruit…"
101
+ /></ui-autocomplete-input>
102
+ <ui-autocomplete-content hidden>
103
+ <ui-autocomplete-list>
104
+ <ui-autocomplete-item value="Apple">Apple</ui-autocomplete-item>
105
+ <ui-autocomplete-item value="Banana">Banana</ui-autocomplete-item>
106
+ </ui-autocomplete-list>
107
+ </ui-autocomplete-content>
108
+ </ui-autocomplete>
109
+ ```
110
+
111
+ ## Autocomplete vs Combobox
112
+
113
+ Both filter a list as you type. They differ in what the value is.
114
+
115
+ - **Autocomplete**: the value is the text. Suggestions help fill it in, and anything typed is valid. Use it for a search box, an address or a free-form field.
116
+ - **[Combobox](./combobox.md)**: the value is an option from the list, or several with `multiple`. The text is only a query; closing without choosing restores the selected label, and a form submits the value, not the text. Use it for a country, an assignee or a set of labels.
117
+
118
+ ## Build Your Own
119
+
120
+ `@ui-sdk/web/autocomplete` comes with ready-made `ui-autocomplete` elements. If you'd like to build your own, with your own element names, start from the `autocomplete` primitive in `@ui-sdk/core`:
121
+
122
+ ```ts title="fruit-search-elements.ts"
123
+ import { autocomplete } from "@ui-sdk/core/autocomplete"
124
+ import { createParts, wrappedChild } from "@ui-sdk/web"
125
+
126
+ createParts(autocomplete, {
127
+ root: "fruit-search",
128
+ label: "fruit-label",
129
+ input: {
130
+ tag: "fruit-input",
131
+ target: wrappedChild("input"),
132
+ display: "contents",
133
+ },
134
+ content: "fruit-popup",
135
+ list: "fruit-list",
136
+ item: "fruit-option",
137
+ empty: "fruit-empty",
138
+ })
139
+ ```
140
+
141
+ ```html
142
+ <fruit-search>
143
+ <fruit-label>Fruit</fruit-label>
144
+ <fruit-input><input /></fruit-input>
145
+ <fruit-popup hidden>
146
+ <fruit-empty>No fruits found.</fruit-empty>
147
+ <fruit-list>
148
+ <fruit-option value="Apple">Apple</fruit-option>
149
+ <fruit-option value="Mango">Mango</fruit-option>
150
+ </fruit-list>
151
+ </fruit-popup>
152
+ </fruit-search>
153
+ ```
154
+
155
+ Each element keeps the behavior, state and data attributes of its ready-made counterpart: typing filters the options, arrow keys move the highlight and the popup opens in the top layer. See [Rendering](../rendering.md) and [Custom Parts](../custom-parts.md) for more.
156
+
157
+ ## Disabled
158
+
159
+ A disabled field cannot be focused or changed and submits nothing. A read-only field stays focusable and submits its value, but does not open or accept changes. Disabled suggestions are skipped by keyboard navigation and cannot fill in the field.
160
+
161
+ ```ts title="disabled.ts"
162
+ import "@ui-sdk/web/autocomplete"
163
+
164
+ const fruits = [
165
+ "Apple",
166
+ "Apricot",
167
+ "Avocado",
168
+ "Banana",
169
+ "Blackberry",
170
+ "Blueberry",
171
+ "Cherry",
172
+ "Grape",
173
+ "Lemon",
174
+ "Mango",
175
+ "Orange",
176
+ "Peach",
177
+ "Pear",
178
+ "Pineapple",
179
+ "Strawberry",
180
+ ]
181
+
182
+ function mount(root: HTMLElement) {
183
+ root.innerHTML = `
184
+ <div data-slot="stack">
185
+ <ui-autocomplete disabled default-value="Banana">
186
+ <div data-slot="stack">
187
+ <ui-autocomplete-label>Disabled</ui-autocomplete-label>
188
+ <ui-autocomplete-input>
189
+ <input />
190
+ </ui-autocomplete-input>
191
+ </div>
192
+ </ui-autocomplete>
193
+ <ui-autocomplete read-only default-value="Cherry">
194
+ <div data-slot="stack">
195
+ <ui-autocomplete-label>Read-only</ui-autocomplete-label>
196
+ <ui-autocomplete-input>
197
+ <input />
198
+ </ui-autocomplete-input>
199
+ </div>
200
+ </ui-autocomplete>
201
+ <ui-autocomplete>
202
+ <div data-slot="stack">
203
+ <ui-autocomplete-label>Some suggestions disabled</ui-autocomplete-label>
204
+ <ui-autocomplete-input>
205
+ <input placeholder="Type “b”" />
206
+ </ui-autocomplete-input>
207
+ </div>
208
+ <ui-autocomplete-content hidden>
209
+ <ui-autocomplete-list>
210
+ ${fruits
211
+ .map(
212
+ (fruit, index) =>
213
+ `<ui-autocomplete-item value="${fruit}" ${index % 3 === 0 ? "disabled" : ""}>${fruit}</ui-autocomplete-item>`
214
+ )
215
+ .join("")}
216
+ </ui-autocomplete-list>
217
+ </ui-autocomplete-content>
218
+ </ui-autocomplete>
219
+ </div>
220
+ `
221
+ }
222
+
223
+ export { mount }
224
+ ```
225
+
226
+ Try the Disabled and Read-only fields. In Disabled suggestion, type “b”: arrow keys skip Banana and a press cannot choose it.
227
+
228
+ ## Clear and Trigger
229
+
230
+ `ui-autocomplete-clear` empties the field and returns focus to it. `ui-autocomplete-trigger` lets someone open the suggestions without typing. Give the trigger a label that describes what it opens.
231
+
232
+ ```ts title="clear.ts"
233
+ import "@ui-sdk/web/autocomplete"
234
+ import { ChevronDown, createElement, X } from "lucide"
235
+
236
+ const fruits = [
237
+ "Apple",
238
+ "Apricot",
239
+ "Avocado",
240
+ "Banana",
241
+ "Blackberry",
242
+ "Blueberry",
243
+ "Cherry",
244
+ "Grape",
245
+ "Lemon",
246
+ "Mango",
247
+ "Orange",
248
+ "Peach",
249
+ "Pear",
250
+ "Pineapple",
251
+ "Strawberry",
252
+ ]
253
+
254
+ function mount(root: HTMLElement) {
255
+ root.innerHTML = `
256
+ <ui-autocomplete default-value="Mango">
257
+ <div data-slot="stack">
258
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
259
+ <div data-slot="row">
260
+ <ui-autocomplete-input>
261
+ <input />
262
+ </ui-autocomplete-input>
263
+ <ui-autocomplete-clear>
264
+ <button aria-label="Clear">${createElement(X, { "aria-hidden": "true" }).outerHTML}</button>
265
+ </ui-autocomplete-clear>
266
+ <ui-autocomplete-trigger>
267
+ <button aria-label="Show fruits">${createElement(ChevronDown, { "aria-hidden": "true" }).outerHTML}</button>
268
+ </ui-autocomplete-trigger>
269
+ </div>
270
+ </div>
271
+ <ui-autocomplete-content hidden>
272
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
273
+ <ui-autocomplete-list>
274
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
275
+ </ui-autocomplete-list>
276
+ </ui-autocomplete-content>
277
+ </ui-autocomplete>
278
+ `
279
+ }
280
+
281
+ export { mount }
282
+ ```
283
+
284
+ Clear Mango, then press Show fruits to open the suggestions. The clear button disappears while the field is empty.
285
+
286
+ ## Open on Focus
287
+
288
+ Add `open-on-focus` to offer suggestions as soon as the input receives focus. This works well when there are useful choices before someone types.
289
+
290
+ ```ts title="open-on-focus.ts"
291
+ import "@ui-sdk/web/autocomplete"
292
+
293
+ const recent = ["react hooks", "tailwind grid", "web components", "vue v-model"]
294
+
295
+ function mount(root: HTMLElement) {
296
+ root.innerHTML = `
297
+ <ui-autocomplete open-on-focus>
298
+ <ui-autocomplete-input>
299
+ <input aria-label="Search" placeholder="Search…" />
300
+ </ui-autocomplete-input>
301
+ <ui-autocomplete-content hidden>
302
+ <ui-autocomplete-empty>No results.</ui-autocomplete-empty>
303
+ <ui-autocomplete-list>
304
+ <ui-autocomplete-group>
305
+ <ui-autocomplete-group-label>Recent searches</ui-autocomplete-group-label>
306
+ ${recent.map((search) => `<ui-autocomplete-item value="${search}">${search}</ui-autocomplete-item>`).join("")}
307
+ </ui-autocomplete-group>
308
+ </ui-autocomplete-list>
309
+ </ui-autocomplete-content>
310
+ </ui-autocomplete>
311
+ `
312
+ }
313
+
314
+ export { mount }
315
+ ```
316
+
317
+ Focus Search docs to see recent searches before typing. Escape closes them; pressing the field opens them again.
318
+
319
+ ## Auto Highlight
320
+
321
+ `auto-highlight` highlights the first match while typing, so Enter can choose it immediately. Set `loop` to `false` to stop arrow keys at either end of the list.
322
+
323
+ ```ts title="auto-highlight.ts"
324
+ import "@ui-sdk/web/autocomplete"
325
+
326
+ const fruits = [
327
+ "Apple",
328
+ "Apricot",
329
+ "Avocado",
330
+ "Banana",
331
+ "Blackberry",
332
+ "Blueberry",
333
+ "Cherry",
334
+ "Grape",
335
+ "Lemon",
336
+ "Mango",
337
+ "Orange",
338
+ "Peach",
339
+ "Pear",
340
+ "Pineapple",
341
+ "Strawberry",
342
+ ]
343
+
344
+ function mount(root: HTMLElement) {
345
+ root.innerHTML = `
346
+ <ui-autocomplete auto-highlight loop="false">
347
+ <div data-slot="stack">
348
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
349
+ <ui-autocomplete-input>
350
+ <input placeholder="Type, then Enter" />
351
+ </ui-autocomplete-input>
352
+ </div>
353
+ <ui-autocomplete-content hidden>
354
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
355
+ <ui-autocomplete-list>
356
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
357
+ </ui-autocomplete-list>
358
+ </ui-autocomplete-content>
359
+ </ui-autocomplete>
360
+ `
361
+ }
362
+
363
+ export { mount }
364
+ ```
365
+
366
+ Type “pe” and press Enter to choose the first match. Arrow keys stop at the ends because this example disables looping.
367
+
368
+ ## Inline Completion
369
+
370
+ `inline-complete` fills in the rest of the first suggestion that starts with the typed text, with the added text selected. Arrow keys fill in the suggestion they highlight. End or Right Arrow accepts the completion; Backspace or Escape takes it back out.
371
+
372
+ ```ts title="inline.ts"
373
+ import "@ui-sdk/web/autocomplete"
374
+
375
+ const fruits = [
376
+ "Apple",
377
+ "Apricot",
378
+ "Avocado",
379
+ "Banana",
380
+ "Blackberry",
381
+ "Blueberry",
382
+ "Cherry",
383
+ "Grape",
384
+ "Lemon",
385
+ "Mango",
386
+ "Orange",
387
+ "Peach",
388
+ "Pear",
389
+ "Pineapple",
390
+ "Strawberry",
391
+ ]
392
+
393
+ function mount(root: HTMLElement) {
394
+ root.innerHTML = `
395
+ <ui-autocomplete inline-complete>
396
+ <div data-slot="stack">
397
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
398
+ <ui-autocomplete-input>
399
+ <input placeholder="Type “bl”" />
400
+ </ui-autocomplete-input>
401
+ </div>
402
+ <ui-autocomplete-content hidden>
403
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
404
+ <ui-autocomplete-list>
405
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
406
+ </ui-autocomplete-list>
407
+ </ui-autocomplete-content>
408
+ </ui-autocomplete>
409
+ `
410
+ }
411
+
412
+ export { mount }
413
+ ```
414
+
415
+ Type “bl” to complete blackberry inline. Backspace removes the completion; Down Arrow fills in Blueberry. Press End to accept the text.
416
+
417
+ ## Highlight Matches
418
+
419
+ `ui-autocomplete-item-text` marks the matching text, ignoring case and accents using the current locale. Each match is a `<mark>` you can style.
420
+
421
+ ```ts title="highlight.ts"
422
+ import "@ui-sdk/web/autocomplete"
423
+
424
+ const fruits = [
425
+ "Apple",
426
+ "Apricot",
427
+ "Avocado",
428
+ "Banana",
429
+ "Blackberry",
430
+ "Blueberry",
431
+ "Cherry",
432
+ "Grape",
433
+ "Lemon",
434
+ "Mango",
435
+ "Orange",
436
+ "Peach",
437
+ "Pear",
438
+ "Pineapple",
439
+ "Strawberry",
440
+ ]
441
+
442
+ function mount(root: HTMLElement) {
443
+ root.innerHTML = `
444
+ <ui-autocomplete>
445
+ <div data-slot="stack">
446
+ <ui-autocomplete-label>Favorite fruit</ui-autocomplete-label>
447
+ <ui-autocomplete-input>
448
+ <input placeholder="e.g. berry" />
449
+ </ui-autocomplete-input>
450
+ </div>
451
+ <ui-autocomplete-content hidden>
452
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
453
+ <ui-autocomplete-list>
454
+ ${fruits
455
+ .map(
456
+ (fruit) => `
457
+ <ui-autocomplete-item value="${fruit}">
458
+ <ui-autocomplete-item-text>${fruit}</ui-autocomplete-item-text>
459
+ </ui-autocomplete-item>
460
+ `
461
+ )
462
+ .join("")}
463
+ </ui-autocomplete-list>
464
+ </ui-autocomplete-content>
465
+ </ui-autocomplete>
466
+ `
467
+ }
468
+
469
+ export { mount }
470
+ ```
471
+
472
+ Type “berry”. The matching letters are bold while each suggestion keeps its original spelling.
473
+
474
+ ## Filter and Keywords
475
+
476
+ The default filter matches text anywhere in a suggestion. Use `"startsWith"` or `"fuzzy"` for a different match, a function for your own filter, or `false` for results already filtered by a server. `keywords` adds searchable text without changing what goes in the field.
477
+
478
+ ```ts title="filter.ts"
479
+ import "@ui-sdk/web/autocomplete"
480
+
481
+ const tags = [
482
+ { value: "feature", label: "feature", keywords: ["enhancement", "request"] },
483
+ { value: "fix", label: "fix", keywords: ["bug", "patch"] },
484
+ { value: "docs", label: "docs", keywords: ["documentation", "readme"] },
485
+ { value: "performance", label: "performance", keywords: ["speed", "slow"] },
486
+ { value: "security", label: "security", keywords: ["vulnerability"] },
487
+ { value: "refactor", label: "refactor", keywords: ["cleanup"] },
488
+ ]
489
+
490
+ function mount(root: HTMLElement) {
491
+ root.innerHTML = `
492
+ <ui-autocomplete filter="startsWith">
493
+ <div data-slot="stack">
494
+ <ui-autocomplete-label>Tag</ui-autocomplete-label>
495
+ <ui-autocomplete-input>
496
+ <input placeholder="Try “bug”" />
497
+ </ui-autocomplete-input>
498
+ </div>
499
+ <ui-autocomplete-content hidden>
500
+ <ui-autocomplete-empty>No tags found.</ui-autocomplete-empty>
501
+ <ui-autocomplete-list>
502
+ ${tags
503
+ .map(
504
+ (tag) => `
505
+ <ui-autocomplete-item value="${tag.value}" label="${tag.label}" keywords="${tag.keywords.join(",")}">
506
+ ${tag.label}
507
+ <span data-slot="hint">${tag.keywords[0]}</span>
508
+ </ui-autocomplete-item>
509
+ `
510
+ )
511
+ .join("")}
512
+ </ui-autocomplete-list>
513
+ </ui-autocomplete-content>
514
+ </ui-autocomplete>
515
+ `
516
+ }
517
+
518
+ export { mount }
519
+ ```
520
+
521
+ Type “bug” to find fix through its keywords. Type “re” to find labels or keywords that start with those letters.
522
+
523
+ ## Groups
524
+
525
+ Use `ui-autocomplete-group` and `ui-autocomplete-group-label` to name related suggestions. Filtering hides empty groups and separators.
526
+
527
+ ```ts title="groups.ts"
528
+ import "@ui-sdk/web/autocomplete"
529
+
530
+ const fruitGroups = [
531
+ {
532
+ label: "Tree fruits",
533
+ items: ["Apple", "Apricot", "Cherry", "Lemon", "Peach", "Pear"],
534
+ },
535
+ {
536
+ label: "Berries",
537
+ items: ["Blackberry", "Blueberry", "Grape", "Strawberry"],
538
+ },
539
+ { label: "Tropical", items: ["Avocado", "Banana", "Mango", "Pineapple"] },
540
+ ]
541
+
542
+ function mount(root: HTMLElement) {
543
+ root.innerHTML = `
544
+ <ui-autocomplete>
545
+ <div data-slot="stack">
546
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
547
+ <ui-autocomplete-input>
548
+ <input placeholder="e.g. Pear" />
549
+ </ui-autocomplete-input>
550
+ </div>
551
+ <ui-autocomplete-content hidden>
552
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
553
+ <ui-autocomplete-list>
554
+ ${fruitGroups
555
+ .map(
556
+ (group, index) => `
557
+ ${index > 0 ? `<ui-autocomplete-separator></ui-autocomplete-separator>` : ""}
558
+ <ui-autocomplete-group>
559
+ <ui-autocomplete-group-label>${group.label}</ui-autocomplete-group-label>
560
+ ${group.items.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
561
+ </ui-autocomplete-group>
562
+ `
563
+ )
564
+ .join("")}
565
+ </ui-autocomplete-list>
566
+ </ui-autocomplete-content>
567
+ </ui-autocomplete>
568
+ `
569
+ }
570
+
571
+ export { mount }
572
+ ```
573
+
574
+ Type “an”. Banana and Mango remain in Tropical; groups with no matches disappear.
575
+
576
+ ## Icons
577
+
578
+ `ui-autocomplete-item-icon` keeps decorative icons out of accessible names, filtering, and the text put in the field. Add `mirror` for directional icons. An icon-only suggestion still needs an `aria-label`.
579
+
580
+ ```ts title="icons.ts"
581
+ import "@ui-sdk/web/autocomplete"
582
+ import {
583
+ Archive,
584
+ Clock,
585
+ createElement,
586
+ File,
587
+ Pencil,
588
+ Reply,
589
+ Star,
590
+ } from "lucide"
591
+
592
+ const mailSearches = [
593
+ { value: "Starred", icon: Star },
594
+ { value: "Drafts", icon: Pencil },
595
+ { value: "Replies", icon: Reply, mirror: true },
596
+ { value: "Attachments", icon: File },
597
+ { value: "Archived", icon: Archive },
598
+ { value: "Scheduled", icon: Clock },
599
+ ]
600
+
601
+ function mount(root: HTMLElement) {
602
+ root.innerHTML = `
603
+ <ui-autocomplete>
604
+ <ui-autocomplete-input>
605
+ <input type="search" aria-label="Search mail" placeholder="Search mail…" />
606
+ </ui-autocomplete-input>
607
+ <ui-autocomplete-content hidden>
608
+ <ui-autocomplete-empty>No searches found.</ui-autocomplete-empty>
609
+ <ui-autocomplete-list>
610
+ ${mailSearches
611
+ .map(
612
+ (search) => `
613
+ <ui-autocomplete-item value="${search.value}"><ui-autocomplete-item-icon ${search.mirror ? "mirror" : ""}>${createElement(search.icon, { "aria-hidden": "true" }).outerHTML}</ui-autocomplete-item-icon>${search.value}</ui-autocomplete-item>
614
+ `
615
+ )
616
+ .join("")}
617
+ </ui-autocomplete-list>
618
+ </ui-autocomplete-content>
619
+ </ui-autocomplete>
620
+ `
621
+ }
622
+
623
+ export { mount }
624
+ ```
625
+
626
+ Type “rep” and choose Replies. The icon stays out of the text put in the field.
627
+
628
+ ## Items as Data
629
+
630
+ Map an array into parts when you want to write the markup yourself. This example maps fruit groups and adds a separator between them.
631
+
632
+ ```ts title="data.ts"
633
+ import "@ui-sdk/web/autocomplete"
634
+
635
+ const fruitGroups = [
636
+ {
637
+ label: "Tree fruits",
638
+ fruits: ["Apple", "Apricot", "Cherry", "Lemon", "Peach", "Pear"],
639
+ },
640
+ {
641
+ label: "Berries",
642
+ fruits: ["Blackberry", "Blueberry", "Grape", "Strawberry"],
643
+ },
644
+ { label: "Tropical", fruits: ["Avocado", "Banana", "Mango", "Pineapple"] },
645
+ ]
646
+
647
+ function mount(root: HTMLElement) {
648
+ root.innerHTML = `
649
+ <ui-autocomplete>
650
+ <div data-slot="stack">
651
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
652
+ <ui-autocomplete-input>
653
+ <input placeholder="e.g. Peach" />
654
+ </ui-autocomplete-input>
655
+ </div>
656
+ <ui-autocomplete-content hidden>
657
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
658
+ <ui-autocomplete-list>
659
+ ${fruitGroups
660
+ .map(
661
+ (group, index) => `
662
+ ${index > 0 ? `<ui-autocomplete-separator></ui-autocomplete-separator>` : ""}
663
+ <ui-autocomplete-group>
664
+ <ui-autocomplete-group-label>${group.label}</ui-autocomplete-group-label>
665
+ ${group.fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
666
+ </ui-autocomplete-group>
667
+ `
668
+ )
669
+ .join("")}
670
+ </ui-autocomplete-list>
671
+ </ui-autocomplete-content>
672
+ </ui-autocomplete>
673
+ `
674
+ }
675
+
676
+ export { mount }
677
+ ```
678
+
679
+ Open the list to see three fruit groups. Type “an” to narrow them to Banana and Mango.
680
+
681
+ Pass `items` when the autocomplete needs the whole collection, such as server results or recent searches. Assign it as a property and use a `<template>` to style the generated parts. [Lists and Menus](../lists-and-menus.md) covers the `ListData` format.
682
+
683
+ Suggestions can change while the list is open. The highlight stays with its suggestion, and the typed text stays unchanged. Removing the highlighted suggestion clears the highlight.
684
+
685
+ ## Controlled
686
+
687
+ The value is always a string. Set its initial text with `default-value`, then read or write the element’s `value` property. The popup has a separate `open` property. Listen for `valuechange` and `openchange`; the requested value is in `event.detail.value`. Call `event.preventDefault()` to reject a change. [State and Events](../state-and-events.md) covers controlled state and cancellation.
688
+
689
+ ```ts title="controlled.ts"
690
+ import "@ui-sdk/web/autocomplete"
691
+ import { log } from "./log"
692
+
693
+ const fruits = [
694
+ "Apple",
695
+ "Apricot",
696
+ "Avocado",
697
+ "Banana",
698
+ "Blackberry",
699
+ "Blueberry",
700
+ "Cherry",
701
+ "Grape",
702
+ "Lemon",
703
+ "Mango",
704
+ "Orange",
705
+ "Peach",
706
+ "Pear",
707
+ "Pineapple",
708
+ "Strawberry",
709
+ ]
710
+
711
+ function mount(root: HTMLElement) {
712
+ root.innerHTML = `
713
+ <div data-slot="stack">
714
+ <ui-autocomplete debug>
715
+ <ui-autocomplete-label>Fruit (12 characters at most)</ui-autocomplete-label>
716
+ <ui-autocomplete-input>
717
+ <input />
718
+ </ui-autocomplete-input>
719
+ <ui-autocomplete-content hidden>
720
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
721
+ <ui-autocomplete-list>
722
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
723
+ </ui-autocomplete-list>
724
+ </ui-autocomplete-content>
725
+ </ui-autocomplete>
726
+ </div>
727
+ `
728
+ const autocomplete = root.querySelector("ui-autocomplete")!
729
+ autocomplete.addEventListener("valuechange", (event) => {
730
+ if (event.detail.value.length > 12) {
731
+ return event.preventDefault()
732
+ }
733
+ log(root, `text: ${event.detail.reason}`)
734
+ })
735
+ autocomplete.addEventListener("openchange", (event) => {
736
+ log(
737
+ root,
738
+ `${event.detail.value ? "opened" : "closed"}: ${event.detail.reason}`
739
+ )
740
+ })
741
+ autocomplete.addEventListener("openchangecomplete", (event) => {
742
+ log(root, `${event.detail.value ? "opened" : "closed"} and settled`)
743
+ })
744
+ autocomplete.addEventListener("highlight", (event) => {
745
+ if (event.detail.value) {
746
+ log(root, `highlighted ${event.detail.value}`)
747
+ }
748
+ })
749
+ }
750
+
751
+ export { mount }
752
+ ```
753
+
754
+ Type more than 12 characters and the extra text is refused. The console shows each change and its reason.
755
+
756
+ ## Controller
757
+
758
+ Use the element’s `api` property. It can `setValue()`, `clear()`, `focus()`, `setOpen()`, or read `getValue()` and `isOpen()`. `open()` returns a promise that resolves when the popup closes, including abort and unmount; `close()` closes it. See [Controllers](../controllers.md) for lifecycle and change options.
759
+
760
+ ```ts title="controller.ts"
761
+ import "@ui-sdk/web/autocomplete"
762
+
763
+ const fruits = [
764
+ "Apple",
765
+ "Apricot",
766
+ "Avocado",
767
+ "Banana",
768
+ "Blackberry",
769
+ "Blueberry",
770
+ "Cherry",
771
+ "Grape",
772
+ "Lemon",
773
+ "Mango",
774
+ "Orange",
775
+ "Peach",
776
+ "Pear",
777
+ "Pineapple",
778
+ "Strawberry",
779
+ ]
780
+
781
+ function mount(root: HTMLElement) {
782
+ root.innerHTML = `
783
+ <div data-slot="stack">
784
+ <div data-slot="controls">
785
+ <button type="button" data-action="open" data-size="sm">Open</button>
786
+ <button type="button" data-action="type" data-size="sm">Type “Pea”</button>
787
+ <button type="button" data-action="clear" data-size="sm">Clear</button>
788
+ <button type="button" data-action="focus" data-size="sm">Focus</button>
789
+ </div>
790
+ <ui-autocomplete>
791
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
792
+ <ui-autocomplete-input>
793
+ <input />
794
+ </ui-autocomplete-input>
795
+ <ui-autocomplete-content hidden>
796
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
797
+ <ui-autocomplete-list>
798
+ ${fruits.map((item) => `<ui-autocomplete-item value="${item}">${item}</ui-autocomplete-item>`).join("")}
799
+ </ui-autocomplete-list>
800
+ </ui-autocomplete-content>
801
+ </ui-autocomplete>
802
+ </div>
803
+ `
804
+ const fruit = root.querySelector("ui-autocomplete")!.api
805
+ const actions: Record<string, () => void> = {
806
+ open: () => fruit.open(),
807
+ type: () => fruit.setValue("Pea"),
808
+ clear: () => fruit.clear(),
809
+ focus: () => fruit.focus(),
810
+ }
811
+ for (const button of root.querySelectorAll<HTMLElement>("[data-action]")) {
812
+ button.addEventListener("click", () => actions[button.dataset.action!]())
813
+ }
814
+ }
815
+
816
+ export { mount }
817
+ ```
818
+
819
+ Use the buttons to open the suggestions, type Pea, clear the field or focus it from outside.
820
+
821
+ ## Positioning
822
+
823
+ Use `side`, `align`, offsets, or a custom `anchor` to position the suggestions. `container` chooses where they render, and `keep-mounted` keeps closed content in the DOM. [Popups](../popups.md) covers positioning, portals, animation, and modal behavior.
824
+
825
+ ```ts title="positioning.ts"
826
+ import "@ui-sdk/web/autocomplete"
827
+
828
+ const fruits = [
829
+ "Apple",
830
+ "Apricot",
831
+ "Avocado",
832
+ "Banana",
833
+ "Blackberry",
834
+ "Blueberry",
835
+ ]
836
+
837
+ function mount(root: HTMLElement) {
838
+ root.innerHTML = `
839
+ <div id="autocomplete-positioning-box" data-slot="card">
840
+ <ui-autocomplete modal="pointer" container="#autocomplete-positioning-box">
841
+ <div data-slot="stack">
842
+ <ui-autocomplete-label>Fruit</ui-autocomplete-label>
843
+ <ui-autocomplete-input>
844
+ <input />
845
+ </ui-autocomplete-input>
846
+ </div>
847
+ <ui-autocomplete-content side="top" align="end" side-offset="10" align-offset="-4" collision-padding="8" anchor="#autocomplete-positioning-box" keep-mounted hidden>
848
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
849
+ <ui-autocomplete-list>
850
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
851
+ </ui-autocomplete-list>
852
+ </ui-autocomplete-content>
853
+ </ui-autocomplete>
854
+ </div>
855
+ `
856
+ }
857
+
858
+ export { mount }
859
+ ```
860
+
861
+ Open the suggestions. They appear above the card, aligned to its end.
862
+
863
+ ## Animation
864
+
865
+ The content has `data-starting-style` while it opens and `data-ending-style` while it closes. Transition from those states, and the popup stays mounted until the exit finishes:
866
+
867
+ ```css
868
+ [data-slot="autocomplete-content"] {
869
+ transition:
870
+ opacity 0.15s,
871
+ translate 0.2s cubic-bezier(0.22, 1, 0.36, 1);
872
+
873
+ &:is([data-starting-style], [data-ending-style]) {
874
+ opacity: 0;
875
+ translate: 0 -6px;
876
+ }
877
+ }
878
+ ```
879
+
880
+ ```ts title="animation.ts"
881
+ import "@ui-sdk/web/autocomplete"
882
+
883
+ const fruits = [
884
+ "Apple",
885
+ "Apricot",
886
+ "Avocado",
887
+ "Banana",
888
+ "Blackberry",
889
+ "Blueberry",
890
+ "Cherry",
891
+ "Grape",
892
+ "Lemon",
893
+ "Mango",
894
+ "Orange",
895
+ "Peach",
896
+ "Pear",
897
+ "Pineapple",
898
+ "Strawberry",
899
+ ]
900
+
901
+ function mount(root: HTMLElement) {
902
+ root.innerHTML = `
903
+ <ui-autocomplete>
904
+ <div data-slot="stack">
905
+ <ui-autocomplete-label>Favorite fruit</ui-autocomplete-label>
906
+ <ui-autocomplete-input>
907
+ <input placeholder="e.g. Mango" />
908
+ </ui-autocomplete-input>
909
+ </div>
910
+ <ui-autocomplete-content hidden>
911
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
912
+ <ui-autocomplete-list>
913
+ ${fruits
914
+ .map(
915
+ (fruit) => `
916
+ <ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>
917
+ `
918
+ )
919
+ .join("")}
920
+ </ui-autocomplete-list>
921
+ </ui-autocomplete-content>
922
+ </ui-autocomplete>
923
+ `
924
+ }
925
+
926
+ export { mount }
927
+ ```
928
+
929
+ Type to open the suggestions. They slide and fade in, and fade out before they unmount.
930
+
931
+ ## Presentation
932
+
933
+ `presentation="sheet"` opens suggestions in a sheet. `"auto"` chooses a sheet on small touch screens and a popover elsewhere, each time the list opens. The server starts with the popover.
934
+
935
+ The same input moves into the sheet’s header. Opening by touch leaves the keyboard closed; tapping the input opens it and expands the sheet. Choosing a suggestion or swiping down closes it. Keyboard and mouse opening preserve input focus.
936
+
937
+ A sheet is modal unless `modal` is `false`. Give it a height, keep suggestions inside `ui-autocomplete-list`, and leave the content’s `translate` alone so dragging can move it. Use `data-presentation` to style both presentations and `--sheet-backdrop` to set the dimmed background.
938
+
939
+ ```ts title="presentation.ts"
940
+ import "@ui-sdk/web/autocomplete"
941
+
942
+ const fruits = [
943
+ "Apple",
944
+ "Apricot",
945
+ "Avocado",
946
+ "Banana",
947
+ "Blackberry",
948
+ "Blueberry",
949
+ "Cherry",
950
+ "Grape",
951
+ "Lemon",
952
+ "Mango",
953
+ "Orange",
954
+ "Peach",
955
+ "Pear",
956
+ "Pineapple",
957
+ "Strawberry",
958
+ ]
959
+
960
+ function mount(root: HTMLElement) {
961
+ root.innerHTML = `
962
+ <ui-autocomplete presentation="sheet">
963
+ <div data-slot="stack">
964
+ <ui-autocomplete-label>Favorite fruit</ui-autocomplete-label>
965
+ <ui-autocomplete-input>
966
+ <input placeholder="e.g. Mango" />
967
+ </ui-autocomplete-input>
968
+ </div>
969
+ <ui-autocomplete-content hidden>
970
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
971
+ <ui-autocomplete-list>
972
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
973
+ </ui-autocomplete-list>
974
+ </ui-autocomplete-content>
975
+ </ui-autocomplete>
976
+ `
977
+ }
978
+
979
+ export { mount }
980
+ ```
981
+
982
+ Open the field to see a sheet. On touch, tap the field in its header to show the keyboard, or swipe down to close it.
983
+
984
+ ## Forms
985
+
986
+ The native input is the form control: `name` gives its submitted key, `required` rejects empty text, and reset restores `default-value`. Text does not have to match a suggestion. Use `form` to associate the field with a form elsewhere in the page.
987
+
988
+ ```ts title="form.ts"
989
+ import "@ui-sdk/web/autocomplete"
990
+ import "@ui-sdk/web/field"
991
+ import { log } from "./log"
992
+
993
+ const fruits = [
994
+ "Apple",
995
+ "Apricot",
996
+ "Avocado",
997
+ "Banana",
998
+ "Blackberry",
999
+ "Blueberry",
1000
+ "Cherry",
1001
+ "Grape",
1002
+ "Lemon",
1003
+ "Mango",
1004
+ "Orange",
1005
+ "Peach",
1006
+ "Pear",
1007
+ "Pineapple",
1008
+ "Strawberry",
1009
+ ]
1010
+
1011
+ function mount(root: HTMLElement) {
1012
+ root.innerHTML = `
1013
+ <form id="order" data-slot="stack">
1014
+ <ui-field>
1015
+ <ui-field-label>Fruit</ui-field-label>
1016
+ <ui-autocomplete name="fruit" form="order" required default-value="Apple">
1017
+ <ui-autocomplete-input>
1018
+ <input />
1019
+ </ui-autocomplete-input>
1020
+ <ui-autocomplete-content hidden>
1021
+ <ui-autocomplete-empty>No fruits found.</ui-autocomplete-empty>
1022
+ <ui-autocomplete-list>
1023
+ ${fruits.map((fruit) => `<ui-autocomplete-item value="${fruit}">${fruit}</ui-autocomplete-item>`).join("")}
1024
+ </ui-autocomplete-list>
1025
+ </ui-autocomplete-content>
1026
+ </ui-autocomplete>
1027
+ <ui-field-description>Any fruit, listed or not.</ui-field-description>
1028
+ <div><ui-field-error></ui-field-error></div>
1029
+ </ui-field>
1030
+ <div data-slot="row">
1031
+ <button type="submit" data-variant="solid">Submit</button>
1032
+ <button type="reset">Reset</button>
1033
+ </div>
1034
+ </form>
1035
+ `
1036
+ const form = root.querySelector("form")!
1037
+ form.addEventListener("submit", (event) => {
1038
+ event.preventDefault()
1039
+ const data = [...new FormData(form)].map(
1040
+ ([name, value]) => `${name}=${value}`
1041
+ )
1042
+ log(root, `Submitted ${data.join("&")}`)
1043
+ })
1044
+ }
1045
+
1046
+ export { mount }
1047
+ ```
1048
+
1049
+ Submit Apple, then choose Mango. Choosing it fills the field without submitting. Reset restores Apple.
1050
+
1051
+ ## Search
1052
+
1053
+ Enter with no suggestion highlighted fires a `submit` event with the text, then allows the surrounding form to submit. Call `preventDefault()` on the `submit` event if your handler already performs the search.
1054
+
1055
+ Choosing a suggestion normally only fills in the field. Add `submit-on-select` to search as soon as someone chooses one.
1056
+
1057
+ ```ts title="search.ts"
1058
+ import "@ui-sdk/web/autocomplete"
1059
+ import { log } from "./log"
1060
+
1061
+ const recent = ["react hooks", "tailwind grid", "web components", "vue v-model"]
1062
+
1063
+ function mount(root: HTMLElement) {
1064
+ root.innerHTML = `
1065
+ <form role="search" data-slot="stack">
1066
+ <ui-autocomplete submit-on-select name="q">
1067
+ <ui-autocomplete-input>
1068
+ <input type="search" aria-label="Search" placeholder="Search…" />
1069
+ </ui-autocomplete-input>
1070
+ <ui-autocomplete-content hidden>
1071
+ <ui-autocomplete-empty>No results.</ui-autocomplete-empty>
1072
+ <ui-autocomplete-list>
1073
+ ${recent.map((search) => `<ui-autocomplete-item value="${search}">${search}</ui-autocomplete-item>`).join("")}
1074
+ </ui-autocomplete-list>
1075
+ </ui-autocomplete-content>
1076
+ </ui-autocomplete>
1077
+ </form>
1078
+ `
1079
+ root
1080
+ .querySelector("form")!
1081
+ .addEventListener("submit", (event) => event.preventDefault())
1082
+ root.querySelector("ui-autocomplete")!.addEventListener("submit", (event) => {
1083
+ log(root, `Searched “${event.detail.value}”`)
1084
+ })
1085
+ }
1086
+
1087
+ export { mount }
1088
+ ```
1089
+
1090
+ Type “kotlin” and press Enter to search. Choose a suggestion to search for that text instead.
1091
+
1092
+ ## Recent Searches
1093
+
1094
+ Pair `emptyItems` with `items` to show one collection while the field is empty and search the full collection once someone types. Add `open-on-focus` to show the recent searches on focus.
1095
+
1096
+ ```ts title="recent.ts"
1097
+ import "@ui-sdk/web/autocomplete"
1098
+
1099
+ const recent = ["react hooks", "tailwind grid", "web components", "vue v-model"]
1100
+ const topics = [
1101
+ ...recent,
1102
+ "react server components",
1103
+ "tailwind colors",
1104
+ "vue router",
1105
+ ]
1106
+ const recentSearches = [
1107
+ { type: "group" as const, label: "Recent searches", items: recent },
1108
+ ]
1109
+
1110
+ function mount(root: HTMLElement) {
1111
+ root.innerHTML = `
1112
+ <ui-autocomplete open-on-focus>
1113
+ <ui-autocomplete-input>
1114
+ <input type="search" aria-label="Search docs" placeholder="Search docs…" />
1115
+ </ui-autocomplete-input>
1116
+ <ui-autocomplete-content hidden>
1117
+ <ui-autocomplete-empty>No topics found.</ui-autocomplete-empty>
1118
+ <ui-autocomplete-list></ui-autocomplete-list>
1119
+ </ui-autocomplete-content>
1120
+ <template>
1121
+ <ui-autocomplete-group>
1122
+ <ui-autocomplete-group-label></ui-autocomplete-group-label>
1123
+ <ui-autocomplete-item>
1124
+ <ui-autocomplete-item-text></ui-autocomplete-item-text>
1125
+ </ui-autocomplete-item>
1126
+ </ui-autocomplete-group>
1127
+ </template>
1128
+ </ui-autocomplete>
1129
+ `
1130
+ const autocomplete = root.querySelector("ui-autocomplete")!
1131
+ autocomplete.announcement = (change) =>
1132
+ change.type === "results"
1133
+ ? `${change.count} ${change.count === 1 ? "topic" : "topics"}`
1134
+ : null
1135
+ autocomplete.emptyItems = recentSearches
1136
+ autocomplete.items = topics
1137
+ }
1138
+
1139
+ export { mount }
1140
+ ```
1141
+
1142
+ Focus the empty field to see Recent searches. Type “react” to search all topics, then clear the text to return to recent searches.
1143
+
1144
+ ## Async Suggestions
1145
+
1146
+ Use [async options](../utilities/async-options.md) to wait for typing to pause and discard stale results. Pass its `items` and `status`, set `filter` to `false`, and send text changes to its `setQuery()` method.
1147
+
1148
+ `ui-autocomplete-status` and `ui-autocomplete-empty` provide loading, error, and empty messages. Without a status part, `announcement` controls what screen readers hear when typing pauses. The `loadmore` event can request another page when scrolling or highlighting reaches the last suggestion.
1149
+
1150
+ ```ts title="async.ts"
1151
+ import { createAsyncOptions } from "@ui-sdk/core/async-options"
1152
+ import "@ui-sdk/web/autocomplete"
1153
+
1154
+ function searchCities(query: string, { signal }: { signal: AbortSignal }) {
1155
+ const cities = [
1156
+ "Amsterdam",
1157
+ "Athens",
1158
+ "Barcelona",
1159
+ "Berlin",
1160
+ "Boston",
1161
+ "Brussels",
1162
+ "Buenos Aires",
1163
+ "Cairo",
1164
+ "Chicago",
1165
+ "Copenhagen",
1166
+ "Dublin",
1167
+ "Lisbon",
1168
+ "London",
1169
+ "Los Angeles",
1170
+ "Madrid",
1171
+ "Paris",
1172
+ "Prague",
1173
+ "Rome",
1174
+ "Seoul",
1175
+ "Tokyo",
1176
+ ]
1177
+ return new Promise<string[]>((resolve, reject) => {
1178
+ const timer = setTimeout(() => {
1179
+ const needle = query.trim().toLowerCase()
1180
+ resolve(cities.filter((city) => city.toLowerCase().startsWith(needle)))
1181
+ }, 300)
1182
+ signal.addEventListener("abort", () => {
1183
+ clearTimeout(timer)
1184
+ reject(new DOMException("Aborted", "AbortError"))
1185
+ })
1186
+ })
1187
+ }
1188
+
1189
+ function mount(root: HTMLElement) {
1190
+ root.innerHTML = `
1191
+ <ui-autocomplete filter="false">
1192
+ <div data-slot="stack">
1193
+ <ui-autocomplete-label>City</ui-autocomplete-label>
1194
+ <ui-autocomplete-input>
1195
+ <input placeholder="e.g. Paris" />
1196
+ </ui-autocomplete-input>
1197
+ </div>
1198
+ <ui-autocomplete-content hidden>
1199
+ <ui-autocomplete-status></ui-autocomplete-status>
1200
+ <ui-autocomplete-empty>No cities start with “<span></span>”.</ui-autocomplete-empty>
1201
+ <ui-autocomplete-list></ui-autocomplete-list>
1202
+ </ui-autocomplete-content>
1203
+ <template>
1204
+ <ui-autocomplete-item>
1205
+ </ui-autocomplete-item>
1206
+ </template>
1207
+ </ui-autocomplete>
1208
+ `
1209
+ const autocomplete = root.querySelector("ui-autocomplete")!
1210
+ const status = root.querySelector("ui-autocomplete-status")!
1211
+ const query = root.querySelector("ui-autocomplete-empty span")!
1212
+ const results = createAsyncOptions(searchCities, { debounce: 200 })
1213
+ const update = () => {
1214
+ const { items, status: loading } = results.getState()
1215
+ autocomplete.items = items
1216
+ autocomplete.setAttribute("status", loading)
1217
+ status.textContent =
1218
+ loading === "loading"
1219
+ ? "Searching…"
1220
+ : items.length
1221
+ ? `${items.length} ${items.length === 1 ? "city" : "cities"}`
1222
+ : ""
1223
+ }
1224
+ results.subscribe(update)
1225
+ update()
1226
+ autocomplete.addEventListener("valuechange", (event) => {
1227
+ query.textContent = event.detail.value
1228
+ results.setQuery(event.detail.value)
1229
+ })
1230
+ autocomplete.addEventListener("loadmore", () => results.loadMore())
1231
+ }
1232
+
1233
+ export { mount }
1234
+ ```
1235
+
1236
+ Type “b” and wait for the city suggestions. Keep typing to replace the search; the status describes the latest results.
1237
+
1238
+ ## Custom Rendering
1239
+
1240
+ Add `as-child` to give a suggestion a different element: the suggestion binds the element inside it. Here each suggestion is a link, so the autocomplete works as a jump-to menu: Enter or a click follows the highlighted link, and the text after the title is a hint that doesn't affect filtering. [Parts and Composition](../parts-and-composition.md) covers the element wrapping API.
1241
+
1242
+ ```ts title="custom-rendering.ts"
1243
+ import "@ui-sdk/web/autocomplete"
1244
+
1245
+ const pages = [
1246
+ { title: "Installation", section: "Get Started", href: "#installation" },
1247
+ { title: "Composition", section: "Concepts", href: "#composition" },
1248
+ { title: "Build Your Own", section: "Concepts", href: "#build-your-own" },
1249
+ { title: "Styling", section: "Guides", href: "#styling" },
1250
+ { title: "API Reference", section: "Reference", href: "#api-reference" },
1251
+ { title: "Accessibility", section: "Reference", href: "#accessibility" },
1252
+ ]
1253
+
1254
+ function mount(root: HTMLElement) {
1255
+ root.innerHTML = `
1256
+ <ui-autocomplete>
1257
+ <div data-slot="stack">
1258
+ <ui-autocomplete-label>Jump to</ui-autocomplete-label>
1259
+ <ui-autocomplete-input>
1260
+ <input placeholder="e.g. Styling" />
1261
+ </ui-autocomplete-input>
1262
+ </div>
1263
+ <ui-autocomplete-content hidden>
1264
+ <ui-autocomplete-empty>No sections found.</ui-autocomplete-empty>
1265
+ <ui-autocomplete-list>
1266
+ ${pages
1267
+ .map(
1268
+ (page) => `
1269
+ <ui-autocomplete-item value="${page.title}" label="${page.title}" as-child>
1270
+ <a href="${page.href}">${page.title}<span data-slot="hint">${page.section}</span></a>
1271
+ </ui-autocomplete-item>
1272
+ `
1273
+ )
1274
+ .join("")}
1275
+ </ui-autocomplete-list>
1276
+ </ui-autocomplete-content>
1277
+ </ui-autocomplete>
1278
+ `
1279
+ }
1280
+
1281
+ export { mount }
1282
+ ```
1283
+
1284
+ Type “sty” and press Enter to jump to the Styling section of this page.
1285
+
1286
+ ## Styling
1287
+
1288
+ Each element has a `data-slot`, such as `autocomplete-content`, and shows its state through the attributes listed under [Data Attributes](#data-attributes).
1289
+
1290
+ The popup exposes sizing and animation variables. `--anchor-width` is the input’s width; use `--available-height` on the content to keep a long list in the viewport.
1291
+
1292
+ While focus stays in the input, use the content’s `data-modality="keyboard"` with an item’s `data-highlighted` to show a keyboard focus indicator on the highlighted suggestion.
1293
+
1294
+ ### `<ui-autocomplete-content>`
1295
+ - `--anchor-width`: Width of the anchor, usually the trigger. Use it to match widths.
1296
+ - `--anchor-height`: Height of the anchor.
1297
+ - `--available-width`: Space beside the popup, up to the viewport edge. Not inherited either.
1298
+ - `--available-height`: Space between the anchor and the viewport edge. Use it for max-height. Not inherited, so a child that needs it copies it on the popup, like `[--list-height:var(--available-height)]`, and reads `max-h-(--list-height)`. The first popup registers both names for the whole page with `CSS.registerProperty`, so they don't inherit anywhere. A page that needs them to inherit calls it first, with `inherits: true`. An `@property` rule can't, since a registration in script wins.
1299
+ - `--transform-origin`: The point on the anchor the popup opens from. Use it to scale from the right place.
1300
+ - `--arrow-offset`: Where the anchor's center falls along the popup's edge, kept `arrowPadding` from the corners. Position a ::before arrow with it.
1301
+ - `--drawer-progress`: While it presents as a sheet: how far open the sheet is, from 0 closed to 1 at its largest snap point. Never past 1.
1302
+ - `--drawer-dim`: While it presents as a sheet: how dim the page behind is, from 0 to 1. The backdrop's opacity follows it.
1303
+ - `--drawer-expand`: While it presents as a sheet: 0 at the second-largest snap point and below, 1 at the largest. With one snap point, the whole travel.
1304
+ - `--drawer-stack`: While it presents as a sheet: how many sheets opened from inside this one are open above it, rising smoothly as each one opens. Push it back with it.
1305
+ - `--sheet-backdrop`: Set it yourself: the color the page dims to while it presents as a sheet. Black at 0.2 by default.
1306
+
1307
+ ### `<ui-autocomplete-viewport>`
1308
+ - `--keyboard-inset`: While it presents as a sheet: how many pixels of the page the on-screen keyboard covers, 0 without one.
1309
+ - `--visual-viewport-width`: While it presents as a sheet: the width of the part of the page you can see.
1310
+ - `--visual-viewport-height`: While it presents as a sheet: the height of the part of the page you can see, above the keyboard.
1311
+ - `--visual-viewport-top`: While it presents as a sheet: how far the part of the page you can see is scrolled from the top of the layout, as when the keyboard pushes it up.
1312
+
1313
+ ## Data Attributes
1314
+
1315
+ ### `<ui-autocomplete-label>`
1316
+ `[data-slot="autocomplete-label"]`
1317
+
1318
+ - `data-disabled`: Present when the field is disabled, by its own prop, a field or a `<fieldset>`.
1319
+ - `data-readonly`: Present when the field is read-only.
1320
+ - `data-required`: Present when the field is required.
1321
+
1322
+ ### `<ui-autocomplete-input>`
1323
+ `[data-slot="autocomplete-input"]`
1324
+
1325
+ - `data-closed`: Present while the suggestions are closed, including while they animate out.
1326
+ - `data-open`: Present while the suggestions are open.
1327
+ - `data-disabled`: Present when the field is disabled, by its own prop, a field or a `<fieldset>`.
1328
+ - `data-readonly`: Present when the field is read-only.
1329
+ - `data-required`: Present when the field is required.
1330
+
1331
+ ### `<ui-autocomplete-trigger>`
1332
+ `[data-slot="autocomplete-trigger"]`
1333
+
1334
+ - `data-closed`: Present while the suggestions are closed, including while they animate out.
1335
+ - `data-open`: Present while the suggestions are open.
1336
+ - `data-disabled`: Present when the field is disabled, by its own prop, a field or a `<fieldset>`.
1337
+ - `data-readonly`: Present when the field is read-only.
1338
+ - `data-required`: Present when the field is required.
1339
+
1340
+ ### `<ui-autocomplete-clear>`
1341
+ `[data-slot="autocomplete-clear"]`
1342
+
1343
+ - `data-disabled`: Present when the field is disabled or read-only.
1344
+
1345
+ ### `<ui-autocomplete-content>`
1346
+ `[data-slot="autocomplete-content"]`
1347
+
1348
+ - `data-closed`: Present while the suggestions are closed, including while they animate out.
1349
+ - `data-presentation` (`popover`, `sheet`): How the suggestions present this time they're open.
1350
+ - `data-open`: Present while the suggestions are open.
1351
+ - `data-starting-style`: Present for the first frame. Style the state you animate from.
1352
+ - `data-ending-style`: Present while the list animates out. Style the state you animate to.
1353
+ - `data-modality` (`keyboard`, `pointer`): Whether the keyboard or a pointer moves the highlight. Style a focus ring for the keyboard only.
1354
+ - `data-has-icons`: Present while any suggestion inside holds an icon part, so items without one can line up.
1355
+
1356
+ ### `<ui-autocomplete-item>`
1357
+ `[data-slot="autocomplete-item"]`
1358
+
1359
+ - `data-disabled`: Present when the suggestion can't be chosen. Arrow keys skip it.
1360
+ - `data-highlighted`: Present on the highlighted suggestion, which Enter fills in. Focus stays in the field.
1361
+ - `data-has-icon`: Present on a suggestion while it holds an icon part.
1362
+
1363
+ ### `<ui-autocomplete-item-text>`
1364
+ `[data-slot="autocomplete-item-text"]`
1365
+
1366
+ - `data-matched`: Present on a suggestion's text while the field's text matched part of it, which is marked.
1367
+
1368
+ ### `<ui-autocomplete-empty>`
1369
+ `[data-slot="autocomplete-empty"]`
1370
+
1371
+ - `data-loading`: Present while results load, with `status="loading"`.
1372
+ - `data-empty`: Present while no suggestion matches.
1373
+
1374
+ ### `<ui-autocomplete-status>`
1375
+ `[data-slot="autocomplete-status"]`
1376
+
1377
+ - `data-loading`: Present while results load, with `status="loading"`.
1378
+
1379
+ ### `<ui-autocomplete-arrow>`
1380
+ `[data-slot="autocomplete-arrow"]`
1381
+
1382
+ - `data-closed`: Present while the suggestions are closed, including while they animate out.
1383
+ - `data-open`: Present while the suggestions are open.
1384
+
1385
+ ### `<ui-autocomplete-item-icon>`
1386
+ `[data-slot="autocomplete-item-icon"]`
1387
+
1388
+ - `data-mirror`: Present on an icon that flips in right-to-left text, with `mirror`.
1389
+
1390
+ ## API Reference
1391
+
1392
+ Props are attributes in kebab case, like `default-value`, `inline-complete` and `open-on-focus`. `filter`
1393
+ takes `contains`, `startsWith`, `fuzzy` or `false`. `items` and a `filter` function are
1394
+ properties. `container` and `anchor` take CSS selectors. Callbacks are DOM events.
1395
+
1396
+ ### Autocomplete
1397
+
1398
+ - `container?` (`DocumentFragment | Element | null`): Renders the popup into this element instead of in place, like a container inside a shadow root or an iframe. On web components, a CSS selector. Nested popups stay inside their parent.
1399
+ - `value?` (`string`): The text. Pass it to control it.
1400
+ - `defaultValue?` (`string`): The text at first, when uncontrolled. A form reset returns to it.
1401
+ - `valuechange event`: Runs when the text wants to change: typing, choosing a suggestion, a Clear part, a form reset or a controller. `details.cancel()` keeps it as it was.
1402
+ - `open?` (`boolean`): Whether the suggestions are open. Pass it to control them.
1403
+ - `defaultOpen?` (`boolean`): Whether the suggestions start open, when uncontrolled.
1404
+ - `openchange event`: Runs when the suggestions want to open or close. `details.reason` says why, and `details.cancel()` stops it.
1405
+ - `openchangecomplete event`: Runs once the suggestions have finished opening or closing, after any animation.
1406
+ - `submit event`: Runs with the text when Enter is pressed with no suggestion highlighted, or after choosing one with `submitOnSelect`. The surrounding form submits next, unless the event's `preventDefault()` is called.
1407
+ - `items?` (`ListData<string>`): The suggestions as data. Renders them for you, and filters them without rendering every one.
1408
+ - `emptyItems?` (`ListData<string>`): Suggestions shown instead of `items` while the field is empty, like recent searches, with `openOnFocus`. Groups work, like `{ type: "group", label: "Recent", items }`. Needs `items`.
1409
+ - `filter?` (`SearchFilter<string>`): How typing narrows the suggestions: `"contains"`, `"startsWith"`, `"fuzzy"`, a function of the item and the text, or `false` to keep every one, for results a server already filtered.
1410
+ - `inlineComplete?` (`boolean`): Whether typing completes the text with the first suggestion that starts with it, with the rest selected after the caret: ArrowRight or End accepts it, Backspace and Escape take it back out, and arrow keys fill in the suggestion they highlight.
1411
+ - `autoHighlight?` (`boolean`): Whether the first suggestion is highlighted while typing, so Enter chooses it.
1412
+ - `openOnFocus?` (`boolean`): Whether the suggestions open when the field gets focus, like recent searches, even before anything is typed.
1413
+ - `submitOnSelect?` (`boolean`): Whether choosing a suggestion submits, like a search box: `submit` runs, then the form submits.
1414
+ - `status?` (`AsyncOptionsStatus`): Whether results are loading or failed, for the empty and status parts. Sets `aria-busy` on the list while loading.
1415
+ - `highlight event`: Runs when the highlight moves, with the suggestion's index among the visible ones, so a virtualized list can scroll to it.
1416
+ - `loadmore event`: Runs when the highlight or scrolling reaches the last suggestion, so the next page can load, like `createAsyncOptions`'s `loadMore`. Not again for the same suggestions, unless the last load failed.
1417
+ - `announcement?` (`((change: ListAnnouncement) => string | null | undefined)`): What screen readers hear after typing pauses, when no `AutocompleteStatus` is rendered. Return null for nothing.
1418
+ - `loop?` (`boolean`): Whether arrow keys wrap from the last suggestion to the first.
1419
+ - `modal?` (`"pointer" | boolean`): `false`: the page stays usable while the suggestions are open. `"pointer"`: an outside press only closes them. `true`: also locks scroll and makes the rest of the page inert.
1420
+ - `presentation?` (`PresentationSetting<"popover">`): How the suggestions present. `"sheet"` slides them up from the bottom of the screen with the field in its header, where they can be swiped away, and `"auto"` does that on small touch screens. A tap that opens a sheet leaves the keyboard closed until the field in the header is tapped. Decided each time they open; the server renders `"popover"` for `"auto"`.
1421
+ - `disabled?` (`boolean`): Disables the field like a native input: it can't be focused or changed, and its text isn't submitted.
1422
+ - `readOnly?` (`boolean`): Keeps the field focusable and its text submitted, but stops changes.
1423
+ - `required?` (`boolean`): Blocks form submission while the field is empty, with the browser's own message.
1424
+ - `name?` (`string`): The name the text submits under.
1425
+ - `form?` (`string`): The id of a form to belong to, when the field isn't inside that form.
1426
+ - `controller?` (`object`): Opens, closes, reads and sets the autocomplete from anywhere. Create one with `createAutocompleteController()`.
1427
+ - `dismissible?` (`boolean`): Whether Escape, an outside press, focus or the window leaving, Android's back gesture and a sheet's swipe can close it. Triggers, Close parts and the controller always can. Pass `false` while it holds unsaved work, and ask in `dismissattempt`.
1428
+ - `dismissattempt event`: Runs when `dismissible` refused a dismissal made on purpose: Escape, an outside press, back or a swipe. Focus or the window leaving is refused without it. Ask "Discard changes?" here.
1429
+ - `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.
1430
+
1431
+ ### AutocompleteLabel
1432
+
1433
+ Names the input. `<ui-autocomplete-label>` labels the input, so you don't need a `ui-field`.
1434
+
1435
+ ### AutocompleteInput
1436
+
1437
+ The text field. `<ui-autocomplete-input>` wraps a native `input` and gives it the combobox role.
1438
+
1439
+ ### AutocompleteTrigger
1440
+
1441
+ An optional button that opens and closes the suggestions. `<ui-autocomplete-trigger>` wraps a native `button`.
1442
+
1443
+ ### AutocompleteClear
1444
+
1445
+ - `keepMounted?` (`boolean`): Whether the clear button stays in the page while the field is empty.
1446
+
1447
+ ### AutocompleteContent
1448
+
1449
+ - `side?` (`Side`): Which side of the anchor the popup opens on. Flips to the other side when there isn't room. Which side of the field the suggestions open on.
1450
+ - `align?` (`Align`): How the popup lines up with the anchor along that side. `start` and `end` follow the reading direction. How the suggestions line up with the field along that side.
1451
+ - `sideOffset?` (`number`): Gap between the anchor and the popup, in pixels. Gap between the field and the suggestions, in pixels.
1452
+ - `alignOffset?` (`number`): Shift along the anchor, in pixels. Shift along the field, in pixels.
1453
+ - `collisionPadding?` (`number`): Space to keep from the viewport edges, in pixels.
1454
+ - `arrowPadding?` (`number`): Space to keep between the arrow and the popup's corners, in pixels.
1455
+ - `anchor?` (`string | Anchor | null`): Positions the popup against this instead of its trigger: an element, a CSS selector, a point like `{ x, y }`, or anything with `getBoundingClientRect()`. It's read on every check, so it can move. A controller's `open({ anchor })` wins for that open.
1456
+ - `container?` (`DocumentFragment | Element | null`): Renders the popup into this element instead of in place, like a container inside a shadow root or an iframe. On web components, a CSS selector. Nested popups stay inside their parent.
1457
+ - `keepMounted?` (`boolean`): Whether the suggestions stay in the page, hidden, while closed.
1458
+
1459
+ ### AutocompleteArrow
1460
+
1461
+ An optional arrow pointing at the input. `<ui-autocomplete-arrow>` is positioned on the content's edge.
1462
+
1463
+ ### AutocompleteStatus
1464
+
1465
+ Announces loading and result counts to screen readers. `<ui-autocomplete-status>` announces the text you put in it.
1466
+
1467
+ ### AutocompleteEmpty
1468
+
1469
+ Shows when no suggestion matches. `<ui-autocomplete-empty>` stays hidden while there are matches.
1470
+
1471
+ ### AutocompleteList
1472
+
1473
+ Holds the suggestions. `<ui-autocomplete-list>` is the listbox, and renders `items` when you set them.
1474
+
1475
+ ### AutocompleteGroup
1476
+
1477
+ Groups related suggestions. `<ui-autocomplete-group>` has the group role.
1478
+
1479
+ ### AutocompleteGroupLabel
1480
+
1481
+ Names its group. `<ui-autocomplete-group-label>` labels the group.
1482
+
1483
+ ### AutocompleteItem
1484
+
1485
+ - `value` (`string`): Identifies the suggestion. Choosing it fills the field with its `label`, or with this when there's none.
1486
+ - `label?` (`string`): The text the field gets and filtering matches, when the content isn't plain text. Not the accessible name: use `aria-label` for that.
1487
+ - `keywords?` (`string[]`): More words filtering matches.
1488
+ - `disabled?` (`boolean`): Keeps the suggestion from being chosen. Sets `data-disabled` and `aria-disabled`.
1489
+ - `index?` (`number`): The suggestion's position among all visible ones, for virtualized lists that render only some. Sets `aria-posinset` and `aria-setsize`.
1490
+
1491
+ ### AutocompleteItemIcon
1492
+
1493
+ - `mirror?` (`boolean`): Flips the icon horizontally in right-to-left text, for icons that point a way, like arrows and chevrons. Icons that picture a thing, like a clock or a check, stay as they are.
1494
+
1495
+ ### AutocompleteItemText
1496
+
1497
+ The suggestion's text, with the matched part in `<mark>`. `<ui-autocomplete-item-text>` holds text only.
1498
+
1499
+ ### AutocompleteSeparator
1500
+
1501
+ A divider between suggestions or groups. `<ui-autocomplete-separator>` has the separator role.
1502
+
1503
+ ### Items as Data
1504
+
1505
+ Each suggestion in `items`, or a plain string. Groups are `{ type: "group", label, items }` and separators `{ type: "separator" }`.
1506
+
1507
+ - `value` (`T`): Identifies the item, and is what choosing it reports. A string, or any value with `itemToValue`.
1508
+ - `label` (`string`): The text shown and matched by typeahead and filtering. A select's trigger shows it once chosen.
1509
+ - `keywords?` (`string[]`): More words filtering matches, like `["team"]` for a plan called Pro.
1510
+ - `disabled?` (`boolean`): Keeps the item from being chosen. The keyboard skips it, like in a native select.
1511
+
1512
+ The whole array is a `ListData`.
1513
+
1514
+ ### State
1515
+
1516
+ The same state shows as data attributes on each element.
1517
+
1518
+ `AutocompleteInput` and `AutocompleteTrigger`:
1519
+
1520
+ - `open` (`boolean`): Whether the suggestions are open.
1521
+ - `disabled` (`boolean`): Whether the field is disabled, by itself or by a `<fieldset>`.
1522
+ - `readOnly` (`boolean`): Whether the field is read-only.
1523
+ - `required` (`boolean`): Whether the field is required.
1524
+
1525
+ `AutocompleteContent` and `AutocompleteList`:
1526
+
1527
+ - `open` (`boolean`): Whether the suggestions are open. False while they animate out.
1528
+ - `presentation` (`"popover" | "sheet"`): How they present this time they're open.
1529
+ - `status` (`AsyncOptionsStatus`): Whether results are loading or failed.
1530
+ - `items` (`ListData<string>`): The visible suggestions, for rendering a virtualized list yourself.
1531
+
1532
+ `AutocompleteItem`:
1533
+
1534
+ - `highlighted` (`boolean`): Whether the suggestion is highlighted, by the keyboard or the pointer.
1535
+ - `disabled` (`boolean`): Whether the suggestion can't be chosen.
1536
+
1537
+ `AutocompleteEmpty`:
1538
+
1539
+ - `loading` (`boolean`): Whether results are loading.
1540
+ - `empty` (`boolean`): Whether no item matches.
1541
+ - `query` (`string`): The text the list is filtered by.
1542
+
1543
+ `AutocompleteStatus`:
1544
+
1545
+ - `status` (`"idle" | "loading" | "error"`): Whether results are loading or failed.
1546
+ - `loading` (`boolean`): Whether results are loading.
1547
+ - `count` (`number`): How many items are visible.
1548
+
1549
+ `AutocompleteClear`:
1550
+
1551
+ - `disabled` (`boolean`): Whether the field is disabled or read-only.
1552
+
1553
+ `AutocompleteArrow`:
1554
+
1555
+ - `open` (`boolean`): Whether the suggestions are open.
1556
+
1557
+ `AutocompleteItemText`, which takes no props of its own:
1558
+
1559
+ - `segments` (`MatchSegment[]`): The text in pieces, each marked when it matched. Joined, they're the whole text.
1560
+ - `matched` (`boolean`): Whether any piece matched.
1561
+
1562
+ `AutocompleteItemIcon`:
1563
+
1564
+ - `mirror` (`boolean`): Whether it flips in right-to-left text.
1565
+
1566
+ ### Reasons
1567
+
1568
+ Why the text changed:
1569
+
1570
+ - `input-change` (`Event`): Typing, pasting or dropping changed a text field's value; in a combobox it can also open or close it, or Enter keeps the typed text as the value.
1571
+ - `item-press` (`MouseEvent | KeyboardEvent`): A member of a collection was chosen: a menu item, a tab, a radio or a checkbox item.
1572
+ - `list-navigation` (`KeyboardEvent`): Arrow, Home or End keys moved the selection, typing picked an item, or Ctrl or ⌘ with A selected every item of a listbox.
1573
+ - `escape-key` (`KeyboardEvent`): Escape, or a submenu's close key (ArrowLeft in left-to-right layouts).
1574
+ - `clear-press` (`MouseEvent | KeyboardEvent`): A Clear part was pressed, like on an input, a select or a combobox.
1575
+ - `reset` (`none`): A form reset.
1576
+ - `imperative` (`none`): A controller or `api` call, or a property set on a web component.
1577
+
1578
+ And why the suggestions opened or closed:
1579
+
1580
+ - `input-change` (`Event`): Typing, pasting or dropping changed a text field's value; in a combobox it can also open or close it, or Enter keeps the typed text as the value.
1581
+ - `item-press` (`MouseEvent | KeyboardEvent`): A member of a collection was chosen: a menu item, a tab, a radio or a checkbox item.
1582
+ - `escape-key` (`KeyboardEvent`): Escape, or a submenu's close key (ArrowLeft in left-to-right layouts).
1583
+ - `imperative` (`none`): A controller or `api` call, or a property set on a web component.
1584
+ - `trigger-press` (`MouseEvent | KeyboardEvent | TouchEvent`): Click, tap, Enter or Space on the part that opens, closes or toggles. Arrow keys that open a menu or submenu count too. A tap on a combobox's input that opens a sheet reports its `touchend`.
1585
+ - `trigger-focus` (`FocusEvent`): Keyboard focus reached a trigger that opens on focus, like a tooltip's.
1586
+ - `input-commit` (`KeyboardEvent | FocusEvent`): Enter, or leaving a number input, committed what was typed: a number input parses, clamps and snaps it to the step, and an autocomplete closes its suggestions on it.
1587
+ - `outside-press` (`MouseEvent`): A press outside the layer.
1588
+ - `close-press` (`MouseEvent | KeyboardEvent | SubmitEvent`): A Close part was pressed, or a form with `method="dialog"` was submitted.
1589
+ - `focus-out` (`KeyboardEvent | FocusEvent`): Focus left the layer, or Tab moved it out.
1590
+ - `window-blur` (`FocusEvent`): The window lost focus.
1591
+ - `back` (`Event`): Going back: the Android back button or gesture, or Backspace in an empty command input, which returns to the previous page.
1592
+ - `swipe` (`TouchEvent | PointerEvent`): A swipe gesture: a finger, mouse or pen dragged it.
1593
+
1594
+ With `dismissible` false, the refused dismissals `dismissattempt` reports:
1595
+
1596
+ - `escape-key` (`KeyboardEvent`): Escape, or a submenu's close key (ArrowLeft in left-to-right layouts).
1597
+ - `outside-press` (`MouseEvent`): A press outside the layer.
1598
+ - `back` (`Event`): Going back: the Android back button or gesture, or Backspace in an empty command input, which returns to the previous page.
1599
+ - `swipe` (`TouchEvent | PointerEvent`): A swipe gesture: a finger, mouse or pen dragged it.
1600
+
1601
+ ### Controller
1602
+
1603
+ The element's `api` property has the same methods.
1604
+
1605
+ - `isOpen()` (`() => boolean`): Whether the suggestions are open.
1606
+ - `setOpen(open, options?)` (`(open: boolean, options?: AutocompleteChangeOptions<AutocompleteOpenChangeReason> | undefined) => boolean`): Opens or closes the suggestions. Returns false when the change was canceled or it was already open or closed.
1607
+ - `open(options?)` (`(options?: (AutocompleteChangeOptions<AutocompleteOpenChangeReason> & { signal?: AbortSignal | undefined; }) | undefined) => Promise<...>`): Opens the suggestions, and resolves once they close, with why and how. Resolves exactly once and never rejects: on the next close, when `signal` aborts, or with reason `"unmount"`.
1608
+ - `close(options?)` (`(options?: AutocompleteChangeOptions<AutocompleteOpenChangeReason> | undefined) => boolean`): Closes the suggestions. Returns false when the close was canceled or it was already closed.
1609
+ - `toggle(options?)` (`(options?: AutocompleteChangeOptions<AutocompleteOpenChangeReason> | undefined) => boolean`): Opens the suggestions when they're closed, and closes them when they're open. Returns false when the change was canceled.
1610
+ - `getValue()` (`() => string`): The text.
1611
+ - `setValue(value, options?)` (`(value: string, options?: AutocompleteChangeOptions<AutocompleteValueChangeReason> | undefined) => boolean`): Changes the text, which filters the suggestions. Returns false when the change was canceled or nothing changed.
1612
+ - `clear(options?)` (`(options?: AutocompleteChangeOptions<AutocompleteValueChangeReason> | undefined) => boolean`): Empties the field. Returns false when the change was canceled or nothing changed.
1613
+ - `focus()` (`() => void`): Moves focus to the field.
1614
+
1615
+ ### Events
1616
+
1617
+ Events fire on `<ui-autocomplete>` and don't bubble, with the new state in `event.detail.value` and the `reason` and `event` beside it. Calling `preventDefault()` on `valuechange` or `openchange` cancels the change.
1618
+
1619
+ | Member | On | Description |
1620
+ | -------------------------- | ----------------- | --------------------------------------------------------------- |
1621
+ | `value` property | `ui-autocomplete` | The text. Setting it changes the text, as a controller would |
1622
+ | `open` property, attribute | `ui-autocomplete` | Whether the suggestions are open |
1623
+ | `api` property | `ui-autocomplete` | The [controller](#controller-1) |
1624
+ | `valuechange` event | `ui-autocomplete` | `detail: { value, reason, event, source }` |
1625
+ | `openchange` event | `ui-autocomplete` | `detail: { value: open, reason, event, source }` |
1626
+ | `openchangecomplete` event | `ui-autocomplete` | `detail: { value: open }`, after the animation |
1627
+ | `highlight` event | `ui-autocomplete` | `detail: { value, index, event }` |
1628
+ | `loadmore` event | `ui-autocomplete` | When the last suggestion is reached |
1629
+ | `submit` event | `ui-autocomplete` | `detail: { value }`. Cancel it to keep the form from submitting |
1630
+ | `dismissattempt` event | `ui-autocomplete` | `detail: { reason, event }`, when a dismissal was refused |
1631
+
1632
+ ## Accessibility
1633
+
1634
+ The autocomplete follows the [WAI-ARIA combobox pattern with list autocomplete](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/), and [list and inline](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both/) with `inline-complete`.
1635
+
1636
+ Typing filters the suggestions. Arrow keys move the highlight; Enter fills in the highlighted text and Escape closes the list. Focus usually stays in the input while `aria-activedescendant` identifies the highlighted suggestion. A touch screen-reader trigger can move focus into the list, and a sheet has its own [focus behavior](#presentation).
1637
+
1638
+ Every line below is an automated test.
1639
+
1640
+ **Field**
1641
+
1642
+ - Is a combobox named by its label, with list autocomplete.
1643
+ - Typing opens the suggestions that match, and the text stays what was typed.
1644
+ - Text that matches nothing stays, with the empty message.
1645
+ - Typing in the middle of the text keeps the caret where it was.
1646
+
1647
+ **Choosing**
1648
+
1649
+ - Arrow keys move the highlight while focus stays in the field.
1650
+ - Enter fills in the highlighted suggestion and closes, without submitting.
1651
+ - Clicking a suggestion fills it in and keeps focus in the field.
1652
+ - A disabled suggestion can't be chosen.
1653
+ - Escape takes an inline completion back out.
1654
+ - Escape closes the suggestions and keeps the text.
1655
+
1656
+ **Forms**
1657
+
1658
+ - Enter with nothing highlighted submits the text as typed.
1659
+ - The field submits a chosen suggestion's text under its name.
1660
+ - Required blocks submitting an empty field.
1661
+ - A disabled field can't be focused or changed.
1662
+
1663
+ **Clear**
1664
+
1665
+ - The clear button empties the field and keeps focus in it.
1666
+
1667
+ Runs in React, Vue and web components.
1668
+
1669
+ Also tested:
1670
+
1671
+ **Enhancements**
1672
+
1673
+ - Inline completion fills in the first match with the rest selected after the caret.
1674
+ - Backspace takes an inline completion out and doesn't complete again.
1675
+ - ArrowRight accepts an inline completion.
1676
+ - With inline completion, arrow keys fill in the suggestion they highlight.
1677
+ - The suggestions open when the field gets focus.
1678
+ - Enter with nothing highlighted runs onSubmit with the text.
1679
+ - Filtering matches a suggestion's keywords.
1680
+ - A form reset puts the default text back.
1681
+ - The list is named by the field's label.
1682
+ - An immediate search runs once when the autocomplete mounts.
1683
+ - A newer search aborts the older one, and only its results land.
1684
+ - Arrow keys keep the highlighted item in view when the … scrolls.
1685
+
1686
+ Runs in React, Vue and web components.
1687
+
1688
+ Screen readers hear the same thing in each tested framework, recorded by a virtual screen reader:
1689
+
1690
+ - Announcements while typing and choosing with a keyboard.
1691
+
1692
+ Runs in React, Vue and web components.