@lifesg/react-design-system 4.0.0-alpha.12 → 4.0.0-alpha.14

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 (323) hide show
  1. package/breadcrumb/breadcrumb.js +1 -1
  2. package/breadcrumb/breadcrumb.js.map +1 -1
  3. package/breadcrumb/breadcrumb.styles.d.ts +0 -8
  4. package/breadcrumb/breadcrumb.styles.js +1 -1
  5. package/breadcrumb/breadcrumb.styles.js.map +1 -1
  6. package/breadcrumb/breadcrumb.styles_1blzn8n.css +7 -0
  7. package/breadcrumb/types.d.ts +2 -13
  8. package/cjs/breadcrumb/breadcrumb.js +1 -1
  9. package/cjs/breadcrumb/breadcrumb.js.map +1 -1
  10. package/cjs/breadcrumb/breadcrumb.styles.js +1 -1
  11. package/cjs/breadcrumb/breadcrumb.styles.js.map +1 -1
  12. package/cjs/breadcrumb/breadcrumb.styles_1blzn8n.css +7 -0
  13. package/cjs/drawer/drawer.js +1 -1
  14. package/cjs/drawer/drawer.js.map +1 -1
  15. package/cjs/drawer/drawer.styles.js +1 -1
  16. package/cjs/drawer/drawer.styles.js.map +1 -1
  17. package/{drawer/drawer.styles_94hx3y.css → cjs/drawer/drawer.styles_a4bwe0.css} +6 -3
  18. package/cjs/external/dompurify/dist/purify.es.js +4 -2
  19. package/cjs/external/dompurify/dist/purify.es.js.map +1 -1
  20. package/cjs/file-upload/file-list/file-list.js +1 -1
  21. package/cjs/file-upload/file-list/file-list.js.map +1 -1
  22. package/cjs/file-upload/file-list/file-list.styles.js +1 -1
  23. package/cjs/file-upload/file-list/file-list.styles.js.map +1 -1
  24. package/cjs/file-upload/file-list/file-list.styles_1xbypnh.css +2 -0
  25. package/cjs/file-upload/file-list-item/file-item-actions.js +2 -0
  26. package/cjs/file-upload/file-list-item/file-item-actions.js.map +1 -0
  27. package/cjs/file-upload/file-list-item/file-item-actions.styles.js +2 -0
  28. package/cjs/file-upload/file-list-item/file-item-actions.styles.js.map +1 -0
  29. package/cjs/file-upload/file-list-item/file-item-actions.styles_1quulgy.css +8 -0
  30. package/cjs/file-upload/file-list-item/file-item-details.js +2 -0
  31. package/cjs/file-upload/file-list-item/file-item-details.js.map +1 -0
  32. package/cjs/file-upload/file-list-item/file-item-details.styles.js +2 -0
  33. package/cjs/file-upload/file-list-item/file-item-details.styles.js.map +1 -0
  34. package/cjs/file-upload/file-list-item/file-item-details.styles_1ce9akx.css +7 -0
  35. package/cjs/file-upload/file-list-item/file-list-item.js +1 -1
  36. package/cjs/file-upload/file-list-item/file-list-item.js.map +1 -1
  37. package/cjs/file-upload/file-list-item/file-list-item.styles.js +1 -1
  38. package/cjs/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
  39. package/cjs/file-upload/file-list-item/file-list-item.styles_x3a500.css +10 -0
  40. package/cjs/file-upload/file-list-item/use-truncated-name.js +2 -0
  41. package/cjs/file-upload/file-list-item/use-truncated-name.js.map +1 -0
  42. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
  43. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
  44. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +1 -1
  45. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
  46. package/{local-nav/local-nav-dropdown/local-nav-dropdown.styles_uhd4xl.css → cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles_kpel1m.css} +9 -6
  47. package/cjs/local-nav/local-nav-menu/local-nav-menu.js +1 -1
  48. package/cjs/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
  49. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js +1 -1
  50. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
  51. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles_67fcyc.css +8 -0
  52. package/cjs/menu/menu-content.js +1 -1
  53. package/cjs/menu/menu-content.js.map +1 -1
  54. package/cjs/menu/menu-content.styles.js +1 -1
  55. package/cjs/menu/menu-content.styles.js.map +1 -1
  56. package/cjs/menu/menu-content.styles_1r8oxtk.css +5 -0
  57. package/cjs/menu/menu-item.styles.js +1 -1
  58. package/cjs/menu/menu-item.styles.js.map +1 -1
  59. package/cjs/menu/{menu-item.styles_liyed8.css → menu-item.styles_eut2j9.css} +1 -1
  60. package/cjs/menu/menu-link.styles.js +1 -1
  61. package/cjs/menu/menu-link.styles.js.map +1 -1
  62. package/cjs/menu/menu-link.styles_rng7n7.css +2 -0
  63. package/cjs/menu/menu-section.js +1 -1
  64. package/cjs/menu/menu-section.js.map +1 -1
  65. package/cjs/menu/menu-section.styles.js +1 -1
  66. package/cjs/menu/menu-section.styles.js.map +1 -1
  67. package/cjs/menu/menu-section.styles_1n0ppxl.css +5 -0
  68. package/cjs/modal-v2/slots/slot-styles.js +1 -1
  69. package/cjs/modal-v2/slots/slot-styles.js.map +1 -1
  70. package/cjs/modal-v2/slots/{slot-styles_ayb9il.css → slot-styles_ygu6zc.css} +1 -1
  71. package/cjs/navbar/navbar-items.js +1 -1
  72. package/cjs/navbar/navbar-items.js.map +1 -1
  73. package/cjs/notification-banner/notification-banner-hoc.js +1 -1
  74. package/cjs/notification-banner/notification-banner-hoc.js.map +1 -1
  75. package/cjs/pagination/pagination.js +1 -1
  76. package/cjs/pagination/pagination.js.map +1 -1
  77. package/cjs/shared/dropdown-list/dropdown-label.js +1 -1
  78. package/cjs/shared/dropdown-list/dropdown-label.js.map +1 -1
  79. package/cjs/shared/fade-wrapper/fade-wrapper.js +1 -1
  80. package/cjs/shared/fade-wrapper/fade-wrapper.js.map +1 -1
  81. package/cjs/theme/tokens/colour.js +1 -1
  82. package/cjs/theme/tokens/colour.js.map +1 -1
  83. package/cjs/theme/tokens/radius.js +1 -1
  84. package/cjs/theme/tokens/radius.js.map +1 -1
  85. package/codemods/run-codemod.js +8 -2
  86. package/codemods/run-codemod.js.map +1 -1
  87. package/codemods/run-codemod.ts +13 -4
  88. package/drawer/drawer.d.ts +1 -1
  89. package/drawer/drawer.js +1 -1
  90. package/drawer/drawer.js.map +1 -1
  91. package/drawer/drawer.styles.d.ts +3 -0
  92. package/drawer/drawer.styles.js +1 -1
  93. package/drawer/drawer.styles.js.map +1 -1
  94. package/{cjs/drawer/drawer.styles_94hx3y.css → drawer/drawer.styles_a4bwe0.css} +6 -3
  95. package/drawer/types.d.ts +7 -0
  96. package/external/dompurify/dist/purify.es.js +4 -2
  97. package/external/dompurify/dist/purify.es.js.map +1 -1
  98. package/file-upload/file-list/file-list.js +1 -1
  99. package/file-upload/file-list/file-list.js.map +1 -1
  100. package/file-upload/file-list/file-list.styles.d.ts +0 -1
  101. package/file-upload/file-list/file-list.styles.js +1 -1
  102. package/file-upload/file-list/file-list.styles.js.map +1 -1
  103. package/file-upload/file-list/file-list.styles_1xbypnh.css +2 -0
  104. package/file-upload/file-list-item/file-item-actions.d.ts +30 -0
  105. package/file-upload/file-list-item/file-item-actions.js +2 -0
  106. package/file-upload/file-list-item/file-item-actions.js.map +1 -0
  107. package/file-upload/file-list-item/file-item-actions.styles.d.ts +6 -0
  108. package/file-upload/file-list-item/file-item-actions.styles.js +2 -0
  109. package/file-upload/file-list-item/file-item-actions.styles.js.map +1 -0
  110. package/file-upload/file-list-item/file-item-actions.styles_1quulgy.css +8 -0
  111. package/file-upload/file-list-item/file-item-details.d.ts +15 -0
  112. package/file-upload/file-list-item/file-item-details.js +2 -0
  113. package/file-upload/file-list-item/file-item-details.js.map +1 -0
  114. package/file-upload/file-list-item/file-item-details.styles.d.ts +7 -0
  115. package/file-upload/file-list-item/file-item-details.styles.js +2 -0
  116. package/file-upload/file-list-item/file-item-details.styles.js.map +1 -0
  117. package/file-upload/file-list-item/file-item-details.styles_1ce9akx.css +7 -0
  118. package/file-upload/file-list-item/file-list-item.d.ts +1 -7
  119. package/file-upload/file-list-item/file-list-item.js +1 -1
  120. package/file-upload/file-list-item/file-list-item.js.map +1 -1
  121. package/file-upload/file-list-item/file-list-item.styles.d.ts +6 -13
  122. package/file-upload/file-list-item/file-list-item.styles.js +1 -1
  123. package/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
  124. package/file-upload/file-list-item/file-list-item.styles_x3a500.css +10 -0
  125. package/file-upload/file-list-item/types.d.ts +10 -3
  126. package/file-upload/file-list-item/use-truncated-name.d.ts +1 -0
  127. package/file-upload/file-list-item/use-truncated-name.js +2 -0
  128. package/file-upload/file-list-item/use-truncated-name.js.map +1 -0
  129. package/input-group/types.d.ts +4 -1
  130. package/input-select/types.d.ts +1 -0
  131. package/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
  132. package/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
  133. package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.d.ts +3 -0
  134. package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +1 -1
  135. package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
  136. package/{cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles_uhd4xl.css → local-nav/local-nav-dropdown/local-nav-dropdown.styles_kpel1m.css} +9 -6
  137. package/local-nav/local-nav-menu/local-nav-menu.js +1 -1
  138. package/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
  139. package/local-nav/local-nav-menu/local-nav-menu.styles.d.ts +3 -0
  140. package/local-nav/local-nav-menu/local-nav-menu.styles.js +1 -1
  141. package/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
  142. package/local-nav/local-nav-menu/local-nav-menu.styles_67fcyc.css +8 -0
  143. package/local-nav/types.d.ts +17 -0
  144. package/masked-input/types.d.ts +1 -2
  145. package/menu/menu-content.js +1 -1
  146. package/menu/menu-content.js.map +1 -1
  147. package/menu/menu-content.styles.d.ts +1 -0
  148. package/menu/menu-content.styles.js +1 -1
  149. package/menu/menu-content.styles.js.map +1 -1
  150. package/menu/menu-content.styles_1r8oxtk.css +5 -0
  151. package/menu/menu-item.styles.js +1 -1
  152. package/menu/menu-item.styles.js.map +1 -1
  153. package/menu/{menu-item.styles_liyed8.css → menu-item.styles_eut2j9.css} +1 -1
  154. package/menu/menu-link.styles.js +1 -1
  155. package/menu/menu-link.styles.js.map +1 -1
  156. package/menu/menu-link.styles_rng7n7.css +2 -0
  157. package/menu/menu-section.d.ts +1 -1
  158. package/menu/menu-section.js +1 -1
  159. package/menu/menu-section.js.map +1 -1
  160. package/menu/menu-section.styles.d.ts +7 -0
  161. package/menu/menu-section.styles.js +1 -1
  162. package/menu/menu-section.styles.js.map +1 -1
  163. package/menu/menu-section.styles_1n0ppxl.css +5 -0
  164. package/menu/menu.d.ts +1 -1
  165. package/menu/types.d.ts +10 -2
  166. package/modal-v2/slots/slot-styles.js +1 -1
  167. package/modal-v2/slots/slot-styles.js.map +1 -1
  168. package/modal-v2/slots/{slot-styles_ayb9il.css → slot-styles_ygu6zc.css} +1 -1
  169. package/navbar/navbar-items.js +1 -1
  170. package/navbar/navbar-items.js.map +1 -1
  171. package/navbar/types.d.ts +9 -0
  172. package/notification-banner/notification-banner-hoc.js +1 -1
  173. package/notification-banner/notification-banner-hoc.js.map +1 -1
  174. package/package.json +3 -4
  175. package/pagination/pagination.js +1 -1
  176. package/pagination/pagination.js.map +1 -1
  177. package/pagination/types.d.ts +8 -1
  178. package/scripts/cli.js +18 -0
  179. package/select-histogram/types.d.ts +1 -0
  180. package/shared/dropdown-list/dropdown-label.d.ts +2 -2
  181. package/shared/dropdown-list/dropdown-label.js +1 -1
  182. package/shared/dropdown-list/dropdown-label.js.map +1 -1
  183. package/shared/dropdown-list/types.d.ts +6 -2
  184. package/shared/fade-wrapper/fade-wrapper.js +1 -1
  185. package/shared/fade-wrapper/fade-wrapper.js.map +1 -1
  186. package/shared/fade-wrapper/types.d.ts +1 -0
  187. package/shared/styles/index.d.ts +5 -0
  188. package/skills/fds-build/SKILL.md +167 -0
  189. package/skills/fds-build/catalogue.md +181 -0
  190. package/skills/fds-build/evals/evals.json +519 -0
  191. package/skills/fds-build/resources/components/accordion.md +128 -0
  192. package/skills/fds-build/resources/components/alert.md +54 -0
  193. package/skills/fds-build/resources/components/animation.md +18 -0
  194. package/skills/fds-build/resources/components/avatar.md +10 -0
  195. package/skills/fds-build/resources/components/badge.md +18 -0
  196. package/skills/fds-build/resources/components/box-container.md +61 -0
  197. package/skills/fds-build/resources/components/breadcrumb.md +60 -0
  198. package/skills/fds-build/resources/components/button.md +74 -0
  199. package/skills/fds-build/resources/components/calendar.md +113 -0
  200. package/skills/fds-build/resources/components/card.md +43 -0
  201. package/skills/fds-build/resources/components/checkbox.md +53 -0
  202. package/skills/fds-build/resources/components/countdown-timer.md +20 -0
  203. package/skills/fds-build/resources/components/data-table.md +142 -0
  204. package/skills/fds-build/resources/components/date-navigator.md +25 -0
  205. package/skills/fds-build/resources/components/divider.md +23 -0
  206. package/skills/fds-build/resources/components/drawer.md +78 -0
  207. package/skills/fds-build/resources/components/error-display.md +137 -0
  208. package/skills/fds-build/resources/components/feedback-rating.md +61 -0
  209. package/skills/fds-build/resources/components/file-download.md +54 -0
  210. package/skills/fds-build/resources/components/file-upload.md +105 -0
  211. package/skills/fds-build/resources/components/filter.md +228 -0
  212. package/skills/fds-build/resources/components/footer.md +94 -0
  213. package/skills/fds-build/resources/components/form-date-input.md +85 -0
  214. package/skills/fds-build/resources/components/form-date-range-input.md +146 -0
  215. package/skills/fds-build/resources/components/form-e-signature.md +55 -0
  216. package/skills/fds-build/resources/components/form-input.md +65 -0
  217. package/skills/fds-build/resources/components/form-masked-input.md +69 -0
  218. package/skills/fds-build/resources/components/form-multi-select.md +100 -0
  219. package/skills/fds-build/resources/components/form-nested-multi-select.md +159 -0
  220. package/skills/fds-build/resources/components/form-nested-select.md +151 -0
  221. package/skills/fds-build/resources/components/form-otp-verification.md +175 -0
  222. package/skills/fds-build/resources/components/form-phone-number-input.md +87 -0
  223. package/skills/fds-build/resources/components/form-predictive-text-input.md +108 -0
  224. package/skills/fds-build/resources/components/form-select.md +103 -0
  225. package/skills/fds-build/resources/components/form-slider.md +116 -0
  226. package/skills/fds-build/resources/components/form-textarea.md +116 -0
  227. package/skills/fds-build/resources/components/form-time-range-picker.md +98 -0
  228. package/skills/fds-build/resources/components/form-timepicker.md +77 -0
  229. package/skills/fds-build/resources/components/form-unit-number-input.md +138 -0
  230. package/skills/fds-build/resources/components/fullscreen-image-carousel.md +159 -0
  231. package/skills/fds-build/resources/components/histogram-slider.md +41 -0
  232. package/skills/fds-build/resources/components/icon.md +167 -0
  233. package/skills/fds-build/resources/components/image-button.md +12 -0
  234. package/skills/fds-build/resources/components/input.md +51 -0
  235. package/skills/fds-build/resources/components/language-switcher.md +15 -0
  236. package/skills/fds-build/resources/components/layout.md +156 -0
  237. package/skills/fds-build/resources/components/link-list.md +120 -0
  238. package/skills/fds-build/resources/components/local-nav.md +119 -0
  239. package/skills/fds-build/resources/components/masthead.md +14 -0
  240. package/skills/fds-build/resources/components/menu.md +109 -0
  241. package/skills/fds-build/resources/components/modal.md +150 -0
  242. package/skills/fds-build/resources/components/navbar.md +270 -0
  243. package/skills/fds-build/resources/components/notification-banner.md +106 -0
  244. package/skills/fds-build/resources/components/pagination.md +104 -0
  245. package/skills/fds-build/resources/components/pill.md +55 -0
  246. package/skills/fds-build/resources/components/popover.md +80 -0
  247. package/skills/fds-build/resources/components/progress-indicator.md +47 -0
  248. package/skills/fds-build/resources/components/radio-button.md +66 -0
  249. package/skills/fds-build/resources/components/schedule.md +78 -0
  250. package/skills/fds-build/resources/components/sidenav.md +183 -0
  251. package/skills/fds-build/resources/components/singpass-button.md +14 -0
  252. package/skills/fds-build/resources/components/smart-app-banner.md +28 -0
  253. package/skills/fds-build/resources/components/tab.md +107 -0
  254. package/skills/fds-build/resources/components/table.md +65 -0
  255. package/skills/fds-build/resources/components/tag.md +68 -0
  256. package/skills/fds-build/resources/components/text-list.md +44 -0
  257. package/skills/fds-build/resources/components/time-slot-bar-week.md +66 -0
  258. package/skills/fds-build/resources/components/time-slot-bar.md +57 -0
  259. package/skills/fds-build/resources/components/time-slot-week-view.md +70 -0
  260. package/skills/fds-build/resources/components/timeline.md +69 -0
  261. package/skills/fds-build/resources/components/timetable.md +123 -0
  262. package/skills/fds-build/resources/components/toast.md +72 -0
  263. package/skills/fds-build/resources/components/toggle.md +119 -0
  264. package/skills/fds-build/resources/components/typography.md +86 -0
  265. package/skills/fds-build/resources/components/uneditable-section.md +84 -0
  266. package/skills/fds-build/resources/foundations/layout-composition-patterns.md +53 -0
  267. package/skills/fds-build/resources/foundations/tokens.md +547 -0
  268. package/skills/fds-build/resources/patterns/states.md +300 -0
  269. package/skills/fds-build/resources/setup/setup.md +202 -0
  270. package/skills/fds-build/resources/templates/form.md +427 -0
  271. package/skills/fds-build/resources/templates/listing.md +435 -0
  272. package/theme/styles/a11y-playground.css +52 -40
  273. package/theme/styles/bookingsg.css +52 -40
  274. package/theme/styles/careercompass.css +52 -40
  275. package/theme/styles/ccube.css +52 -40
  276. package/theme/styles/imda.css +52 -40
  277. package/theme/styles/lifesg.css +52 -40
  278. package/theme/styles/mylegacy.css +52 -40
  279. package/theme/styles/oneservice.css +52 -40
  280. package/theme/styles/pa.css +28 -22
  281. package/theme/styles/rbs.css +52 -40
  282. package/theme/styles/sgw-digital-lobby.css +52 -40
  283. package/theme/styles/smgs.css +52 -40
  284. package/theme/styles/spf.css +28 -27
  285. package/theme/styles/sportsg-orange.css +52 -40
  286. package/theme/styles/supportgowhere.css +52 -40
  287. package/theme/styles/tote-board.css +52 -40
  288. package/theme/styles/vica.css +52 -40
  289. package/theme/styles/websg.css +52 -40
  290. package/theme/styles/wise.css +52 -40
  291. package/theme/styles/wogaa.css +52 -40
  292. package/theme/tokens/colour.d.ts +6 -0
  293. package/theme/tokens/colour.js +1 -1
  294. package/theme/tokens/colour.js.map +1 -1
  295. package/theme/tokens/radius.d.ts +3 -0
  296. package/theme/tokens/radius.js +1 -1
  297. package/theme/tokens/radius.js.map +1 -1
  298. package/breadcrumb/breadcrumb.styles_1nl4aua.css +0 -18
  299. package/cjs/breadcrumb/breadcrumb.styles_1nl4aua.css +0 -18
  300. package/cjs/file-upload/file-item-edit.js +0 -2
  301. package/cjs/file-upload/file-item-edit.js.map +0 -1
  302. package/cjs/file-upload/file-item-edit.styles.js +0 -2
  303. package/cjs/file-upload/file-item-edit.styles.js.map +0 -1
  304. package/cjs/file-upload/file-item-edit.styles_19bvztn.css +0 -11
  305. package/cjs/file-upload/file-list/file-list.styles_1w7so98.css +0 -3
  306. package/cjs/file-upload/file-list-item/file-list-item.styles_kgtfke.css +0 -17
  307. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles_pq19dh.css +0 -5
  308. package/cjs/menu/menu-content.styles_p7ijll.css +0 -2
  309. package/cjs/menu/menu-link.styles_hfxoez.css +0 -2
  310. package/cjs/menu/menu-section.styles_g7my4d.css +0 -3
  311. package/file-upload/file-item-edit.d.ts +0 -14
  312. package/file-upload/file-item-edit.js +0 -2
  313. package/file-upload/file-item-edit.js.map +0 -1
  314. package/file-upload/file-item-edit.styles.d.ts +0 -9
  315. package/file-upload/file-item-edit.styles.js +0 -2
  316. package/file-upload/file-item-edit.styles.js.map +0 -1
  317. package/file-upload/file-item-edit.styles_19bvztn.css +0 -11
  318. package/file-upload/file-list/file-list.styles_1w7so98.css +0 -3
  319. package/file-upload/file-list-item/file-list-item.styles_kgtfke.css +0 -17
  320. package/local-nav/local-nav-menu/local-nav-menu.styles_pq19dh.css +0 -5
  321. package/menu/menu-content.styles_p7ijll.css +0 -2
  322. package/menu/menu-link.styles_hfxoez.css +0 -2
  323. package/menu/menu-section.styles_g7my4d.css +0 -3
@@ -0,0 +1,51 @@
1
+ # Input
2
+
3
+ Import: `import { Input } from "@lifesg/react-design-system/input"`
4
+
5
+ ## When to use
6
+
7
+ Use `Input` for standalone inputs that do not need a label or error message — search bars, inline editing, filter fields, or composition contexts where the form layout is provided externally. For all labelled form fields with validation messages, use `Form.Input` instead.
8
+
9
+ ## Variants
10
+
11
+ | `styleType` | When to use |
12
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
13
+ | `"bordered"` (default) | Standard standalone input — provides clear affordance |
14
+ | `"no-border"` | Inline editing or search bars embedded in headers/toolbars where a border would conflict with the surrounding UI |
15
+
16
+ ## Props — `InputProps`
17
+
18
+ | Prop | Type | Default | Description |
19
+ | ------------ | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
20
+ | `spacing` | `number` | — | Inserts a space after every `spacing` characters in the displayed value. Only applies when `type` is `"tel"`. |
21
+ | `error` | `boolean` | — | Marks the input wrapper in an error state. |
22
+ | `allowClear` | `boolean` | false | Shows a clear button when the field has a value and is neither disabled nor read-only. |
23
+ | `onClear` | `() => void` | — | Called when the user activates the clear button. Use this to clear the controlled value. |
24
+ | `styleType` | `InputStyleType` | "bordered" | Visual style variant. |
25
+
26
+ ## Props — `InputPartialProps`
27
+
28
+ | Prop | Type | Default | Description |
29
+ | ------------ | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
30
+ | `spacing` | `number` | — | Inserts a space after every `spacing` characters in the displayed value. Only applies when `type` is `"tel"`. |
31
+ | `allowClear` | `boolean` | false | Shows a clear button when the field has a value and is neither disabled nor read-only. |
32
+ | `onClear` | `() => void` | — | Called when the user activates the clear button. Use this to clear the controlled value. |
33
+ | `styleType` | `InputStyleType` | "bordered" | Visual style variant. |
34
+
35
+ ## Rules
36
+
37
+ - Use `type="email"` for email fields and `type="tel"` for phone fields — triggers the correct mobile keyboard.
38
+ - Use `spacing` for formatted `tel` inputs (e.g. `spacing={4}` for `9123 4567`) — do not implement custom character splitting.
39
+ - Use `allowClear` for search inputs and optional fields; pair with `onClear` to reset the controlled value.
40
+ - Set `error={true}` to communicate an invalid state visually — provide a separate error message element in the surrounding layout.
41
+ - Use `styleType="no-border"` only when the surrounding container or background provides sufficient visual separation.
42
+ - `Input` is the bare input field with no label or error message wrapper. Use `Form.Input` when a label or validation message is needed.
43
+ - `spacing` only has effect when `type="tel"`.
44
+ - `styleType="no-border"` removes the visible border — use only when the surrounding context provides sufficient visual distinction.
45
+ - `error` drives error-state styling only; there is no built-in error message — pair with external error text if needed.
46
+
47
+ ## Anti-patterns
48
+
49
+ - Do not use `Input` inside a form that needs labels or validation messages — use `Form.Input`.
50
+ - Do not use `spacing` with input types other than `"tel"`.
51
+ - Do not rely on `Input` alone to surface error messages — it has no built-in error text slot.
@@ -0,0 +1,15 @@
1
+ # LanguageSwitcher
2
+
3
+ Import: `import { LanguageSwitcher } from "@lifesg/react-design-system/language-switcher"`
4
+
5
+ ## Props — `LanguageSwitcherProps`
6
+
7
+ | Prop | Type | Default | Description |
8
+ | ------------------ | -------------------------------------------- | ---------- | -------------------------------------------------------------------------- |
9
+ | `variant` | `LanguageSwitcherVariant` | "dropdown" | Presentation mode. |
10
+ | `selectedLanguage` | `LanguageSwitcherCode` | "en" | The currently active language code. |
11
+ | `onSelectLanguage` | `((language: LanguageSwitcherCode) => void)` | — | Called when the user selects a language different from `selectedLanguage`. |
12
+
13
+ ## Rules
14
+
15
+ - `LanguageSwitcherCode` is the union of supported language codes: `"en" | "zh" | "ms" | "ta"`.
@@ -0,0 +1,156 @@
1
+ # Layout
2
+
3
+ Import: `import { Layout } from "@lifesg/react-design-system/layout"`
4
+
5
+ ## Composition
6
+
7
+ ```
8
+ Layout.Container type="grid" ← responsive 12-col grid (desktop) / 8-col (mobile)
9
+ ├── Layout.ColDiv xsCols lgCols ← column span — always set xsCols
10
+ ├── Layout.ColDiv xsCols lgCols
11
+ └── Layout.ColDiv xsCols lgCols
12
+
13
+ Layout.Container type="flex" ← horizontal flexbox row
14
+ └── {children}
15
+
16
+ Layout.Container type="flex-column" ← vertical flexbox column
17
+ └── {children}
18
+ ```
19
+
20
+ `Layout.Section` and `Layout.Content` share the same props as `Layout.Container` and can be used in place of it for semantic HTML structure. Never nest `Layout.Container` inside another `Layout.Container`. Always set `xsCols` on every `Layout.ColDiv` — never set only `lgCols`.
21
+
22
+ - `Layout.ColDiv` — responsive grid column div
23
+
24
+ ## Usage
25
+
26
+ ```tsx
27
+ import { Layout } from "@lifesg/react-design-system/layout";
28
+
29
+ <Layout.Container type="grid">
30
+ <Layout.ColDiv xsCols={8} lgCols={6}>
31
+ Content
32
+ </Layout.ColDiv>
33
+ </Layout.Container>;
34
+ ```
35
+
36
+ | `type` | Use case |
37
+ | --------------- | -------------------------------- |
38
+ | `"grid"` | Responsive column grid (default) |
39
+ | `"flex"` | Horizontal flexbox layout |
40
+ | `"flex-column"` | Vertical flexbox layout |
41
+
42
+ ## Breakpoints
43
+
44
+ | Breakpoint | Min width | Columns | Gutter | Device |
45
+ | ---------- | --------- | ------- | ------ | --------------------- |
46
+ | `xxs` | 0px | 8 | 16px | Smallest mobile |
47
+ | `xs` | 321px | 8 | 16px | Small mobile |
48
+ | `sm` | 376px | 8 | 16px | Mobile |
49
+ | `md` | 481px | 8 | 16px | Large mobile / tablet |
50
+ | `lg` | 769px | 12 | 32px | Desktop |
51
+ | `xl` | 1201px | 12 | 32px | Large desktop |
52
+ | `xxl` | 1441px | 12 | 32px | Extra-large |
53
+
54
+ ### Common column widths
55
+
56
+ | Use case | `xsCols` | `lgCols` | `xlCols` |
57
+ | ------------------------------------ | -------- | -------- | -------- |
58
+ | Full width | 8 | 12 | — |
59
+ | Full width (form progress indicator) | 12 | 12 | — |
60
+ | Narrow content (forms) | 12 | 9 | 8 |
61
+ | Half-width (2-up cards) | 8 | 6 | — |
62
+ | Third-width (3-up cards) | 8 | 4 | — |
63
+ | Quarter-width (4-up metrics) | 8 | 6 | 3 |
64
+ | Sidebar | 8 | 3 | — |
65
+ | Main + sidebar main | 8 | 9 | — |
66
+
67
+ ## Responsive styles
68
+
69
+ Use CSS Module classes for responsive styles in v4. The `MediaQuery` breakpoint body classes replace `@media` queries in CSS Modules.
70
+
71
+ ```tsx
72
+ import styles from "./MyComponent.module.css";
73
+
74
+ <div className={styles.responsiveDiv}>...</div>;
75
+ ```
76
+
77
+ ```css
78
+ /* MyComponent.module.css */
79
+ .responsiveDiv {
80
+ padding: var(--fds-spacing-16);
81
+ }
82
+
83
+ :global(body.fds-breakpoint-lg-min) .responsiveDiv {
84
+ padding: var(--fds-spacing-32);
85
+ }
86
+ ```
87
+
88
+ | CSS Module selector | Query type | When it applies |
89
+ | ------------------------------------------ | ------------------- | -------------------------------- |
90
+ | `:global(body.fds-breakpoint-md-min) .cls` | `min-width: 481px` | md and up (tablet+) |
91
+ | `:global(body.fds-breakpoint-lg-min) .cls` | `min-width: 769px` | lg and up (desktop+) |
92
+ | `:global(body.fds-breakpoint-md-max) .cls` | `max-width: 768px` | md and below (mobile only) |
93
+ | `:global(body.fds-breakpoint-lg-max) .cls` | `max-width: 1200px` | lg and below (non-large-desktop) |
94
+
95
+ Design mobile-first — define base styles for mobile, then override with `MinWidth` for larger screens.
96
+
97
+ ## Props — `ContainerProps`
98
+
99
+ | Prop | Type | Default | Description |
100
+ | ------------- | ----------------- | ------- | --------------------------------------------------------- |
101
+ | `type` | `ContainerType` | "flex" | Display mode applied to the container. |
102
+ | `children` \* | `React.ReactNode` | — | — |
103
+ | `stretch` | `boolean` | false | Stretches the element to fill its container's full width. |
104
+
105
+ ## Props — `SectionProps`
106
+
107
+ | Prop | Type | Default | Description |
108
+ | ------------- | ----------------- | ------- | --------------------------------------------------------- |
109
+ | `children` \* | `React.ReactNode` | — | — |
110
+ | `stretch` | `boolean` | false | Stretches the element to fill its container's full width. |
111
+
112
+ ## Props — `ContentProps`
113
+
114
+ | Prop | Type | Default | Description |
115
+ | ------------- | ----------------- | ------- | --------------------------------------------------------- |
116
+ | `type` | `ContainerType` | "flex" | Display mode applied to the container. |
117
+ | `children` \* | `React.ReactNode` | — | — |
118
+ | `stretch` | `boolean` | false | Stretches the element to fill its container's full width. |
119
+
120
+ ## Props — `ColProps`
121
+
122
+ | Prop | Type | Default | Description |
123
+ | --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
124
+ | `xxlCols` | `ColSpan` | — | Column span at the `xxl` breakpoint. |
125
+ | `xlCols` | `ColSpan` | — | Column span at the `xl` breakpoint. |
126
+ | `lgCols` | `ColSpan` | — | Column span at the `lg` breakpoint. |
127
+ | `mdCols` | `ColSpan` | — | Column span at the `md` breakpoint. |
128
+ | `smCols` | `ColSpan` | — | Column span at the `sm` breakpoint. |
129
+ | `xsCols` | `ColSpan` | — | Column span at the `xs` breakpoint. |
130
+ | `xxsCols` | `ColSpan` | — | Column span at the `xxs` (smallest) breakpoint. Acts as the base value. All larger breakpoints fall back to this when their own prop is not set. |
131
+
132
+ ## Props — `ColDivProps`
133
+
134
+ | Prop | Type | Default | Description |
135
+ | --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
136
+ | `xxlCols` | `ColSpan` | — | Column span at the `xxl` breakpoint. |
137
+ | `xlCols` | `ColSpan` | — | Column span at the `xl` breakpoint. |
138
+ | `lgCols` | `ColSpan` | — | Column span at the `lg` breakpoint. |
139
+ | `mdCols` | `ColSpan` | — | Column span at the `md` breakpoint. |
140
+ | `smCols` | `ColSpan` | — | Column span at the `sm` breakpoint. |
141
+ | `xsCols` | `ColSpan` | — | Column span at the `xs` breakpoint. |
142
+ | `xxsCols` | `ColSpan` | — | Column span at the `xxs` (smallest) breakpoint. Acts as the base value. All larger breakpoints fall back to this when their own prop is not set. |
143
+
144
+ ## Rules
145
+
146
+ - Use CSS Modules for component-level styles — do not use plain inline styles for layout concerns.
147
+ - Use `:where(body.fds-breakpoint-{bp}-min)` selectors for responsive styles — never hardcoded pixel breakpoints.
148
+ - Use CSS custom properties for spacing (e.g. `var(--fds-spacing-16)`) — never hardcode pixel values.
149
+
150
+ Grid rules:
151
+
152
+ - Always use `type="grid"` on Container for responsive column layouts.
153
+ - Always specify `xsCols` on ColDiv — mobile-first; never only `lgCols`.
154
+ - Max `xsCols` is 8 (mobile/tablet), max `lgCols` is 12 (desktop).
155
+ - Never nest `Layout.Container` inside another `Layout.Container`.
156
+ - A column span applies to all larger viewports until overridden.
@@ -0,0 +1,120 @@
1
+ # LinkList
2
+
3
+ Import: `import { LinkList } from "@lifesg/react-design-system/link-list"`
4
+
5
+ ## When to use
6
+
7
+ Use to present a set of related links — related articles, resources, or quick-access shortcuts. Use `style="small"` for compact contexts such as sidebars or footnotes.
8
+
9
+ ## Sub-components
10
+
11
+ ### LinkListItemProps
12
+
13
+ | Prop | Type | Default | Description |
14
+ | ---------------------- | ------------------------------------------------------ | ------- | -------------------------------------------------- |
15
+ | `title` | `string` | — | Link label — required |
16
+ | `description` | `string` | — | First-level supporting text below the title |
17
+ | `secondaryDescription` | `string` | — | Second-level supporting text below the description |
18
+ | `options` | `T` | — | Custom properties to pass to the item |
19
+ | `onClick` | `(event: React.MouseEvent<HTMLAnchorElement>) => void` | — | Per-item click handler — overrides `onItemClick` |
20
+ | `data-testid` | `string` | — | Test identifier for the item |
21
+
22
+ Inherits `HTMLAnchorElement` attributes (e.g. `href`, `target`).
23
+
24
+ ### Custom labels
25
+
26
+ | Prop | Type | Default | Description |
27
+ | ---------- | -------- | ------------- | ------------------------------ |
28
+ | `viewMore` | `string` | `"View more"` | Label for the show-more button |
29
+ | `viewLess` | `string` | `"View less"` | Label for the show-less button |
30
+
31
+ ## Variants
32
+
33
+ | `style` | Usage |
34
+ | ----------- | ------------------------------------------------------ |
35
+ | `"default"` | Standard size — use in main content areas |
36
+ | `"small"` | Compact — use in sidebars, footnotes, or dense layouts |
37
+
38
+ | `loadMode` | Usage |
39
+ | ---------- | ------------------------------------------------------------- |
40
+ | `"eager"` | All items loaded upfront; use `maxShown` to collapse the list |
41
+ | `"lazy"` | Items fetched on demand; requires `loadMore` and `onLoadMore` |
42
+
43
+ ## Usage
44
+
45
+ ```tsx
46
+ import { LinkList } from "@lifesg/react-design-system/link-list";
47
+
48
+ <LinkList
49
+ items={[
50
+ {
51
+ title: "Apply for a grant",
52
+ description: "Find out if you qualify.",
53
+ href: "/grants/apply",
54
+ },
55
+ { title: "Check application status", href: "/grants/status" },
56
+ { title: "Download forms", href: "/grants/forms" },
57
+ ]}
58
+ maxShown={2}
59
+ />;
60
+ ```
61
+
62
+ ## Props — `LinkListItemProps`
63
+
64
+ | Prop | Type | Default | Description |
65
+ | ---------------------- | ----------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------- |
66
+ | `title` \* | `string \| JSX.Element` | — | Primary label displayed as the link text. |
67
+ | `description` | `string \| JSX.Element` | — | Secondary text shown below the title. |
68
+ | `secondaryDescription` | `JSX.Element` | — | Additional content rendered below the description. Accepts a JSX element for rich secondary content. |
69
+ | `options` | `T` | — | Arbitrary custom data passed through to the `onItemClick` callback. |
70
+ | `onClick` | `\| ((event: React.MouseEvent<HTMLAnchorElement>) => void)` | — | Called when an item is clicked. This overrides the `onItemClick` event handler. |
71
+
72
+ ## Props — `LinkListBaseProps`
73
+
74
+ | Prop | Type | Default | Description |
75
+ | -------------- | ----------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------- |
76
+ | `items` \* | `LinkListItemProps<T>[]` | — | The list of link items to render. |
77
+ | `style` | `LinkListStyle` | "default" | Visual size variant applied to all items. |
78
+ | `className` | `string` | — | — |
79
+ | `onItemClick` | `\| (( item: LinkListItemProps<T>, event: React.MouseEvent<HTMLAnchorElement> ) => void)` | — | Component-level click handler called for every item click, unless the item defines its own `onClick`. |
80
+ | `customLabels` | `\| { viewMore?: string; viewLess?: string; }` | — | Overrides the default toggle button labels. |
81
+
82
+ ## Props — `LinkListEagerProps`
83
+
84
+ | Prop | Type | Default | Description |
85
+ | ---------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
86
+ | `loadMode` | `"eager"` | — | When `"eager"`, all items are rendered immediately. |
87
+ | `maxShown` | `number` | — | Maximum number of items shown before the list is truncated. Items beyond this count are hidden until the user activates the toggle. When omitted, all items are shown without truncation. |
88
+
89
+ ## Props — `LinkListLazyProps`
90
+
91
+ | Prop | Type | Default | Description |
92
+ | --------------- | ----------------------------- | ------- | ----------------------------------------------------------------------------------------- |
93
+ | `loadMode` \* | `"lazy"` | — | When `"lazy"`, items are loaded on demand. |
94
+ | `loadMore` \* | `boolean` | — | Whether more items are available to load. When `false`, the "View more" button is hidden. |
95
+ | `onLoadMore` \* | `() => void \| Promise<void>` | — | Called when the user activates the "View more" button. |
96
+
97
+ ## Props — `LinkListProps`
98
+
99
+ | Prop | Type | Default | Description |
100
+ | -------------- | ----------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------- |
101
+ | `items` \* | `LinkListItemProps<T>[]` | — | The list of link items to render. |
102
+ | `style` | `LinkListStyle` | "default" | Visual size variant applied to all items. |
103
+ | `className` | `string` | — | — |
104
+ | `onItemClick` | `\| (( item: LinkListItemProps<T>, event: React.MouseEvent<HTMLAnchorElement> ) => void)` | — | Component-level click handler called for every item click, unless the item defines its own `onClick`. |
105
+ | `customLabels` | `\| { viewMore?: string; viewLess?: string; }` | — | Overrides the default toggle button labels. |
106
+ | `loadMode` | `"eager"` | — | When `"eager"`, all items are rendered immediately. |
107
+
108
+ ## Rules
109
+
110
+ - Use `maxShown` when the list has many items to avoid overwhelming the user on first load (eager mode).
111
+ - In `"lazy"` mode, both `loadMore` and `onLoadMore` are required.
112
+ - `onItemClick` applies to all items; per-item `onClick` in `LinkListItemProps` overrides it for that item.
113
+ - Use per-item `onClick` when individual items need different handling; use `onItemClick` for a uniform handler across all items.
114
+ - Use `description` to give users enough context to choose the right link without clicking.
115
+
116
+ ## Anti-patterns
117
+
118
+ - Using lazy mode without providing `onLoadMore` — the "View more" button will be non-functional.
119
+ - Omitting `description` when link titles are ambiguous.
120
+ - Using LinkList for non-link content — use a list or table instead.
@@ -0,0 +1,119 @@
1
+ # LocalNav
2
+
3
+ Import: `import { LocalNavMenu, LocalNavDropdown } from "@lifesg/react-design-system/local-nav"`
4
+
5
+ ## When to use
6
+
7
+ Use to let users navigate between sections on the same page (in-page navigation). Two components exist for different breakpoints — use both together for full responsive coverage.
8
+
9
+ ## Sub-components
10
+
11
+ `LocalNavMenu`, `LocalNavDropdown`
12
+
13
+ ## Variants
14
+
15
+ | Component | Viewport | Behaviour |
16
+ | ------------------ | ----------------- | ---------------------------------------------------------------------- |
17
+ | `LocalNavMenu` | Desktop | Vertical link list fixed to the left of page content, sticky on scroll |
18
+ | `LocalNavDropdown` | Tablet and mobile | Renders inline, then sticks to top of viewport after scroll |
19
+
20
+ ## Usage
21
+
22
+ ```tsx
23
+ import {
24
+ LocalNavMenu,
25
+ LocalNavDropdown,
26
+ } from "@lifesg/react-design-system/local-nav";
27
+
28
+ const navItems = [
29
+ { title: "Overview", id: "overview" },
30
+ { title: "Eligibility", id: "eligibility" },
31
+ { title: "How to apply", id: "how-to-apply" },
32
+ ];
33
+
34
+ {
35
+ /* Desktop */
36
+ }
37
+ <LocalNavMenu
38
+ items={navItems}
39
+ selectedItemIndex={activeIndex}
40
+ onNavItemSelect={(e, item, index) => {}}
41
+ />;
42
+
43
+ {
44
+ /* Mobile / tablet */
45
+ }
46
+ <LocalNavDropdown
47
+ items={navItems}
48
+ selectedItemIndex={activeIndex}
49
+ defaultLabel="Jump to section"
50
+ onNavItemSelect={(e, item, index) => {}}
51
+ />;
52
+ ```
53
+
54
+ ## Props — `TitleAddonProps`
55
+
56
+ | Prop | Type | Default | Description |
57
+ | ------- | ------------- | ------- | ----------------------------------------------------------------------- |
58
+ | `left` | `JSX.Element` | — | Element rendered immediately before the title. |
59
+ | `right` | `JSX.Element` | — | Element rendered after the title, flushed to the far right of the item. |
60
+
61
+ ## Props — `LocalNavItemProps`
62
+
63
+ | Prop | Type | Default | Description |
64
+ | ------------ | --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
65
+ | `title` \* | `string \| React.ReactNode` | — | — |
66
+ | `id` | `string` | — | — |
67
+ | `titleAddon` | `TitleAddonProps` | — | Optional addon element rendered alongside the item title. Ignored when a custom `renderItem` is provided, since the caller then controls the item's layout. |
68
+
69
+ ## Props — `LocalNavMenuItemRenderProps`
70
+
71
+ | Prop | Type | Default | Description |
72
+ | ------------- | --------- | ------- | ------------------------------------------------------------ |
73
+ | `selected` \* | `boolean` | — | Whether this item is the currently selected navigation item. |
74
+
75
+ ## Props — `LocalNavMenuProps`
76
+
77
+ | Prop | Type | Default | Description |
78
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------ |
79
+ | `renderItem` | `\| (( item: LocalNavItemProps, renderProps: LocalNavMenuItemRenderProps ) => React.ReactNode)` | — | Custom renderer for each navigation item. |
80
+ | `className` | `string` | — | — |
81
+ | `id` | `string` | — | — |
82
+ | `onNavItemSelect` \* | `( e: React.MouseEvent<HTMLElement> \| React.KeyboardEvent<HTMLElement>, item: LocalNavItemProps, index: number ) => void` | — | Called when a navigation item is activated. |
83
+ | `items` \* | `LocalNavItemProps[]` | — | The list of navigation items to render. |
84
+ | `selectedItemIndex` | `number` | — | Zero-based index of the currently selected item. |
85
+
86
+ ## Props — `LocalNavDropdownItemRenderProps`
87
+
88
+ | Prop | Type | Default | Description |
89
+ | ------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
90
+ | `selected` \* | `boolean` | — | Whether this item is the currently selected navigation item. |
91
+ | `stickied` \* | `boolean` | — | Whether the dropdown is currently in its stickied (fixed) state. Use this to conditionally style items differently when the nav is pinned. |
92
+
93
+ ## Props — `LocalNavDropdownProps`
94
+
95
+ | Prop | Type | Default | Description |
96
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
97
+ | `defaultLabel` \* | `string \| React.ReactNode` | — | Label shown in the collapsed trigger when no item is selected or when the dropdown is not stickied. Once the dropdown is stickied and an item is selected, the trigger displays the selected item's title instead. |
98
+ | `stickyOffset` | `number` | 0 | Distance in pixels from the top of the viewport while the dropdown is stickied. |
99
+ | `renderItem` | `\| (( item: LocalNavItemProps, renderProps: LocalNavDropdownItemRenderProps ) => React.ReactNode)` | — | Custom renderer for each item in the dropdown list. |
100
+ | `className` | `string` | — | — |
101
+ | `id` | `string` | — | — |
102
+ | `onNavItemSelect` \* | `( e: React.MouseEvent<HTMLElement> \| React.KeyboardEvent<HTMLElement>, item: LocalNavItemProps, index: number ) => void` | — | Called when a navigation item is activated. |
103
+ | `items` \* | `LocalNavItemProps[]` | — | The list of navigation items to render. |
104
+ | `selectedItemIndex` | `number` | — | Zero-based index of the currently selected item. |
105
+
106
+ ## Rules
107
+
108
+ - Use `LocalNavMenu` on desktop and `LocalNavDropdown` on tablet/mobile — render both and show/hide with CSS breakpoints.
109
+ - Always implement scroll-spy: update `selectedItemIndex` as the user scrolls to keep the active item in sync with the visible section. This is not automatic.
110
+ - Place `LocalNavMenu` on the left side of the page content area — not above it.
111
+ - Set `stickyOffset` on `LocalNavDropdown` equal to the height of the fixed Navbar so the dropdown does not overlap it when sticky.
112
+ - Keep item labels short — long labels cause overflow.
113
+ - `defaultLabel` is required on `LocalNavDropdown` — it is the placeholder shown before any item is selected.
114
+
115
+ ## Anti-patterns
116
+
117
+ - Do not use `LocalNavMenu` on tablet or mobile — use `LocalNavDropdown` instead.
118
+ - Do not omit scroll-spy logic — without it, `selectedItemIndex` will not reflect the current section.
119
+ - Do not place `LocalNavMenu` above the content — it must be a left sidebar.
@@ -0,0 +1,14 @@
1
+ # Masthead
2
+
3
+ Import: `import { Masthead } from "@lifesg/react-design-system/masthead"`
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ | --------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
9
+ | `stretch` | `boolean` | false | Allows the masthead to span the full width of its container rather than constraining to the default layout width. |
10
+
11
+ ## Rules
12
+
13
+ - No mandatory props.
14
+ - `Masthead` is typically included via the `Navbar` `masthead` prop — use this standalone component only when rendering the masthead outside a Navbar context.
@@ -0,0 +1,109 @@
1
+ # Menu
2
+
3
+ Import: `import { Menu } from "@lifesg/react-design-system/menu"`
4
+
5
+ ## When to use
6
+
7
+ Use when a trigger element (button, avatar, nav link) should open a floating dropdown with a list of actions or links.
8
+
9
+ Common use cases:
10
+
11
+ - Avatar / user account menu in authenticated dashboards
12
+ - Navbar link dropdown for sub-navigation
13
+
14
+ ## Sub-components
15
+
16
+ `Menu`, `Menu.Content`, `Menu.Section`, `Menu.Item`, `Menu.Link`
17
+
18
+ ## Variants
19
+
20
+ | Use case | Structure |
21
+ | ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
22
+ | User account menu | First section: name + email as `Menu.Item`. Subsequent sections: `Menu.Link` for profile/settings, `Menu.Item` for sign out |
23
+ | Nav link dropdown | Single `Menu.Section` with `Menu.Link` items |
24
+ | Action menu | `Menu.Section` with `Menu.Item` elements and optional `label` |
25
+
26
+ ## Usage
27
+
28
+ ```tsx
29
+ import { Menu } from "@lifesg/react-design-system/menu";
30
+ import { Button } from "@lifesg/react-design-system/button";
31
+
32
+ <Menu
33
+ menuContent={
34
+ <Menu.Content>
35
+ <Menu.Section showDivider={false}>
36
+ <Menu.Link href="/profile">Profile</Menu.Link>
37
+ <Menu.Link href="/settings">Settings</Menu.Link>
38
+ </Menu.Section>
39
+ <Menu.Section>
40
+ <Menu.Item label="Sign out" onClick={() => {}} />
41
+ </Menu.Section>
42
+ </Menu.Content>
43
+ }
44
+ >
45
+ <Button styleType="secondary">Account</Button>
46
+ </Menu>;
47
+ ```
48
+
49
+ ## Props — `MenuProps`
50
+
51
+ | Prop | Type | Default | Description |
52
+ | ------------------ | -------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
53
+ | `menuContent` \* | `FunctionComponentElement<MenuContentProps>` | — | The `Menu.Content` element to display inside the popover panel. |
54
+ | `position` | `PopoverPosition` | "bottom-start" | Preferred placement of the popover relative to the trigger. |
55
+ | `children` \* | `React.ReactNode` | — | The trigger element rendered inside a focusable wrapper div. |
56
+ | `trigger` | `PopoverTriggerType` | "click" | Interaction that opens the popover. |
57
+ | `id` | `string` | — | — |
58
+ | `zIndex` | `number` | — | Overrides the stacking context z-index for the floating popover layer. Falls back to the inherited floating context z-index when omitted. |
59
+ | `className` | `string` | — | — |
60
+ | `rootNode` | `RefObject<HTMLElement>` | document.body | The root element that contains the popover element. |
61
+ | `customOffset` | `number` | 16 | Distance in pixels between the trigger element and the popover panel. |
62
+ | `delay` | `\| { open?: number; close?: number }` | — | Open and close delays in milliseconds. Only applies when `trigger` is `"hover"`. |
63
+ | `enableFlip` | `boolean` | true | Allows the popover to flip to the opposite side when the preferred position has insufficient viewport space. |
64
+ | `enableResize` | `boolean` | false | Resizes the popover to fit the remaining vertical space in the viewport. |
65
+ | `overflow` | `PopoverOverflowType` | "auto" | CSS `overflow` value forwarded to the popover card when `enableResize` is active. |
66
+ | `popoverAriaLabel` | `string` | "More information" | Accessible label for the popover dialog element. |
67
+ | `triggerOnFocus` | `boolean` | false | Also opens the popover when the trigger element receives focus. |
68
+ | `isModal` | `boolean` | true | When `true`, focus is trapped inside the popover until dismissed. When `false`, the popover closes automatically once the user tabs away from both the trigger and the popover. |
69
+ | `onPopoverAppear` | `(() => void)` | — | Called when the popover becomes visible. |
70
+ | `onPopoverDismiss` | `(() => void)` | — | Called when the popover is dismissed. |
71
+
72
+ ## Props — `MenuContentProps`
73
+
74
+ | Prop | Type | Default | Description |
75
+ | ------------- | -------------------------------------------------------------------- | ------- | ---------------------------------------------------------------- |
76
+ | `children` \* | `ReactElement<MenuSectionProps> \| ReactElement<MenuSectionProps>[]` | — | One or more `Menu.Section` elements that make up the panel body. |
77
+ | `overflow` | `PopoverOverflowType` | — | CSS `overflow` value applied to the popover card body. |
78
+ | `maxHeight` | `number` | — | Maximum height of the popover card in pixels. |
79
+
80
+ ## Props — `MenuSectionProps`
81
+
82
+ | Prop | Type | Default | Description |
83
+ | ------------- | -------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
84
+ | `children` \* | `MenuSectionItem \| MenuSectionItem[]` | — | One or more `Menu.Item` or `Menu.Link` elements within this section. |
85
+ | `showDivider` | `boolean` | true | Whether to render a top divider separating this section from the one above. |
86
+ | `columns` | `number` | — | Renders section children in a grid with the given number of columns on desktop. Items flow vertically (top-to-bottom) within each column before wrapping to the next. Has no effect on mobile viewports, which always render as a single column. |
87
+ | `label` | `string` | — | Accessible group label rendered above the section items. |
88
+
89
+ ## Props — `MenuItemProps`
90
+
91
+ | Prop | Type | Default | Description |
92
+ | ---------- | -------- | ------- | -------------------------------------------------- |
93
+ | `label` | `string` | — | Primary text label. |
94
+ | `subLabel` | `string` | — | Secondary descriptive text rendered below `label`. |
95
+
96
+ ## Rules
97
+
98
+ - `Menu` wraps a trigger element as its child — the trigger can be any element (e.g. `Avatar`, `Button`, `NavbarLink`).
99
+ - Pass `Menu.Content` as the `menuContent` prop — not as a child of `Menu`.
100
+ - Use `Menu.Link` for navigation (href-based); use `Menu.Item` for in-page actions (onClick-based).
101
+ - Use `Menu.Section` with `showDivider` to visually separate unrelated groups of actions.
102
+ - For user account menus, always show the user's name and email as the first section.
103
+ - Use `position` to control which side of the trigger the menu appears on; default `"bottom-start"` suits most cases.
104
+
105
+ ## Anti-patterns
106
+
107
+ - Do not pass `Menu.Content` as a child of `Menu` — it must be passed as `menuContent`.
108
+ - Do not mix navigation links and action items in the same `Menu.Section` without a divider.
109
+ - Do not use `Menu.Item` for links that navigate to a new page — use `Menu.Link` instead.