@reliability-design/web 1.4.6 → 1.4.7

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 (146) hide show
  1. package/CHANGELOG.md +211 -49
  2. package/dist/components/rel-accordion/README.md +132 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +156 -61
  5. package/dist/components/rel-avatar/README.md +116 -130
  6. package/dist/components/rel-badge/README.md +98 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +160 -130
  9. package/dist/components/rel-calendar/README.md +109 -109
  10. package/dist/components/rel-card/README.md +75 -94
  11. package/dist/components/rel-cardmedia/README.md +100 -127
  12. package/dist/components/rel-carousel/README.md +184 -166
  13. package/dist/components/rel-checkbox/README.md +93 -75
  14. package/dist/components/rel-chip/README.md +132 -121
  15. package/dist/components/rel-container/README.md +107 -99
  16. package/dist/components/rel-date-picker/README.md +200 -289
  17. package/dist/components/rel-divider/README.md +78 -100
  18. package/dist/components/rel-drawer/README.md +187 -200
  19. package/dist/components/rel-kbd/README.md +141 -151
  20. package/dist/components/rel-menu/README.md +178 -151
  21. package/dist/components/rel-menubar/README.md +218 -329
  22. package/dist/components/rel-otp/README.md +170 -440
  23. package/dist/components/rel-pagination/README.md +100 -424
  24. package/dist/components/rel-popover/README.md +203 -568
  25. package/dist/components/rel-progress/README.md +88 -110
  26. package/dist/components/rel-radio/README.md +131 -138
  27. package/dist/components/rel-range-picker/README.md +162 -0
  28. package/dist/components/rel-resizable/README.md +199 -140
  29. package/dist/components/rel-segmented-button/README.md +155 -141
  30. package/dist/components/rel-select/README.md +154 -93
  31. package/dist/components/rel-sheet/README.md +168 -224
  32. package/dist/components/rel-skeleton/README.md +103 -0
  33. package/dist/components/rel-slider/README.md +130 -135
  34. package/dist/components/rel-snackbar/README.md +162 -134
  35. package/dist/components/rel-stepper/README.md +158 -160
  36. package/dist/components/rel-switch/README.md +108 -102
  37. package/dist/components/rel-tab/README.md +171 -163
  38. package/dist/components/rel-textfield/README.md +159 -69
  39. package/dist/components/rel-time-picker/README.md +122 -157
  40. package/dist/components/rel-toast/README.md +157 -148
  41. package/dist/components/rel-tooltip/README.md +108 -111
  42. package/dist/components/rel-upload/README.md +220 -0
  43. package/dist/index.d.mts +1147 -340
  44. package/dist/index.d.ts +1147 -340
  45. package/dist/index.js +3451 -3163
  46. package/dist/index.js.map +1 -1
  47. package/dist/index.mjs +3416 -3118
  48. package/dist/index.mjs.map +1 -1
  49. package/dist/styles/vars.css +877 -866
  50. package/dist/{vars-XNMTSRVN.css → vars-JHTUGNRG.css} +877 -866
  51. package/package.json +3 -2
  52. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  53. package/dist/components/rel-alert/rel-alert.ts +0 -305
  54. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -720
  55. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  56. package/dist/components/rel-badge/rel-badge.ts +0 -175
  57. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  58. package/dist/components/rel-button/rel-button.ts +0 -560
  59. package/dist/components/rel-calendar/index.ts +0 -1
  60. package/dist/components/rel-calendar/rel-calendar.ts +0 -565
  61. package/dist/components/rel-card/rel-card.ts +0 -88
  62. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  63. package/dist/components/rel-carousel/index.ts +0 -1
  64. package/dist/components/rel-carousel/rel-carousel.ts +0 -723
  65. package/dist/components/rel-chart/README.md +0 -286
  66. package/dist/components/rel-chart/index.ts +0 -1
  67. package/dist/components/rel-chart/rel-chart.ts +0 -754
  68. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  69. package/dist/components/rel-chip/rel-chip.ts +0 -483
  70. package/dist/components/rel-container/rel-container.ts +0 -95
  71. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  72. package/dist/components/rel-date-picker/date-format.ts +0 -47
  73. package/dist/components/rel-date-picker/date-parse.test.ts +0 -116
  74. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  75. package/dist/components/rel-date-picker/index.ts +0 -1
  76. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  77. package/dist/components/rel-divider/rel-divider.ts +0 -54
  78. package/dist/components/rel-drawer/index.ts +0 -1
  79. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  80. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  81. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  82. package/dist/components/rel-layout/rel-layout.ts +0 -49
  83. package/dist/components/rel-menu/rel-menu.ts +0 -541
  84. package/dist/components/rel-menubar/index.ts +0 -2
  85. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  86. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  87. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  88. package/dist/components/rel-nav-menu/README.md +0 -289
  89. package/dist/components/rel-nav-menu/index.ts +0 -3
  90. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  91. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  92. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  93. package/dist/components/rel-navbar/README.md +0 -126
  94. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  95. package/dist/components/rel-otp/index.ts +0 -1
  96. package/dist/components/rel-otp/rel-otp.ts +0 -527
  97. package/dist/components/rel-pagination/index.ts +0 -1
  98. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  99. package/dist/components/rel-popover/index.ts +0 -2
  100. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  101. package/dist/components/rel-popover/rel-popover.ts +0 -475
  102. package/dist/components/rel-progress/rel-progress.ts +0 -234
  103. package/dist/components/rel-radio/rel-radio.ts +0 -481
  104. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  105. package/dist/components/rel-resizable/index.ts +0 -3
  106. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  107. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  108. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  109. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  110. package/dist/components/rel-select/rel-select.ts +0 -1416
  111. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  112. package/dist/components/rel-sidebar/README.md +0 -209
  113. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  114. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  115. package/dist/components/rel-slider/rel-slider.ts +0 -673
  116. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  117. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  118. package/dist/components/rel-switch/rel-switch.ts +0 -199
  119. package/dist/components/rel-tab/rel-tab.ts +0 -264
  120. package/dist/components/rel-table/README.md +0 -178
  121. package/dist/components/rel-table/rel-table-body.ts +0 -22
  122. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  123. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  124. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  125. package/dist/components/rel-table/rel-table-head.ts +0 -47
  126. package/dist/components/rel-table/rel-table-header.ts +0 -22
  127. package/dist/components/rel-table/rel-table-row.ts +0 -37
  128. package/dist/components/rel-table/rel-table.ts +0 -62
  129. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  130. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  131. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  132. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  133. package/dist/components/rel-toast/rel-toast.ts +0 -206
  134. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  135. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  136. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  137. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  138. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  139. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  140. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  141. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  142. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  144. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  145. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  146. package/dist/components/rel-upload/rel-upload.ts +0 -968
@@ -1,329 +1,218 @@
1
- # rel-menubar
2
-
3
- A horizontal menubar component with dropdown menus, submenus, checkbox items, and radio groups. Provides full keyboard navigation and accessibility features.
4
-
5
- ## What It Is
6
-
7
- The menubar component consists of two custom elements:
8
- - `<rel-menubar>` - The root container that manages state and interactions
9
- - `<rel-menubar-menu>` - Individual menu definitions with their content
10
-
11
- Content is authored using semantic HTML with data attributes, allowing the component to enhance it with proper menubar behavior.
12
-
13
- ## Basic Usage
14
-
15
- ```html
16
- <rel-menubar>
17
- <rel-menubar-menu label="File">
18
- <button data-item>New Tab</button>
19
- <button data-item>New Window</button>
20
- <button data-item>Close</button>
21
- </rel-menubar-menu>
22
-
23
- <rel-menubar-menu label="Edit">
24
- <button data-item>Undo</button>
25
- <button data-item>Redo</button>
26
- <div data-separator></div>
27
- <button data-item>Cut</button>
28
- <button data-item>Copy</button>
29
- <button data-item>Paste</button>
30
- </rel-menubar-menu>
31
-
32
- <rel-menubar-menu label="View">
33
- <button data-item>Zoom In</button>
34
- <button data-item>Zoom Out</button>
35
- </rel-menubar-menu>
36
- </rel-menubar>
37
- ```
38
-
39
- ## Submenu Example
40
-
41
- Use `data-submenu` attribute with a `label` attribute to create nested menus:
42
-
43
- ```html
44
- <rel-menubar>
45
- <rel-menubar-menu label="File">
46
- <button data-item>New Tab</button>
47
- <div data-separator></div>
48
- <div data-submenu label="Share">
49
- <button data-item>Email link</button>
50
- <button data-item>Messages</button>
51
- <button data-item>Notes</button>
52
- </div>
53
- <div data-separator></div>
54
- <button data-item>Close</button>
55
- </rel-menubar-menu>
56
- </rel-menubar>
57
- ```
58
-
59
- ## Checkbox Example
60
-
61
- Wrap a checkbox input in a label with `data-checkbox` attribute:
62
-
63
- ```html
64
- <rel-menubar>
65
- <rel-menubar-menu label="View">
66
- <label data-checkbox>
67
- <input type="checkbox" />
68
- Always Show Bookmarks Bar
69
- </label>
70
- <label data-checkbox>
71
- <input type="checkbox" checked />
72
- Always Show Full URLs
73
- </label>
74
- </rel-menubar-menu>
75
- </rel-menubar>
76
- ```
77
-
78
- ## Radio Group Example
79
-
80
- Use `data-radio-group` container with `data-radio` items:
81
-
82
- ```html
83
- <rel-menubar>
84
- <rel-menubar-menu label="Profile">
85
- <div data-radio-group name="user-profile" value="andy">
86
- <button data-radio value="andy">Andy</button>
87
- <button data-radio value="benoit">Benoit</button>
88
- <button data-radio value="luis">Luis</button>
89
- </div>
90
- </rel-menubar-menu>
91
- </rel-menubar>
92
- ```
93
-
94
- ## Shortcuts
95
-
96
- Add keyboard shortcuts as text using the `data-shortcut` attribute:
97
-
98
- ```html
99
- <rel-menubar>
100
- <rel-menubar-menu label="Edit">
101
- <button data-item data-shortcut="Ctrl+Z">Undo</button>
102
- <button data-item data-shortcut="Ctrl+Y">Redo</button>
103
- </rel-menubar-menu>
104
- </rel-menubar>
105
- ```
106
-
107
- Or use `<rel-kbd>` components in the button content for better styling:
108
-
109
- ```html
110
- <rel-menubar>
111
- <rel-menubar-menu label="Edit">
112
- <button data-item>
113
- Undo
114
- <span style="margin-left: auto; display: flex; gap: 4px;">
115
- <rel-kbd size="sm">Ctrl</rel-kbd>
116
- <rel-kbd size="sm">Z</rel-kbd>
117
- </span>
118
- </button>
119
- </rel-menubar-menu>
120
- </rel-menubar>
121
- ```
122
-
123
- ## Data Attributes
124
-
125
- ### Menu Items
126
-
127
- | Attribute | Element | Description |
128
- |-----------|---------|-------------|
129
- | `data-item` | `<button>` | Standard clickable menu item |
130
- | `data-separator` | `<div>` | Visual separator line |
131
- | `data-submenu` | `<div>` | Container for submenu items (requires `label` attribute) |
132
- | `data-checkbox` | `<label>` | Checkbox item (must contain `<input type="checkbox">`) |
133
- | `data-radio-group` | `<div>` | Radio group container (requires `name` and `value` attributes) |
134
- | `data-radio` | `<button>` | Radio button item (requires `value` attribute) |
135
- | `data-shortcut` | `<button>` | Optional keyboard shortcut text |
136
-
137
- ### Properties
138
-
139
- **rel-menubar-menu**
140
- - `label` (string) - The text displayed on the menubar trigger button
141
-
142
- ## Events
143
-
144
- ### rel-menubar-change
145
-
146
- Emitted when a checkbox is toggled or a radio button is selected.
147
-
148
- **Checkbox Event Detail:**
149
- ```typescript
150
- {
151
- type: "checkbox",
152
- label: string, // Label text of the checkbox
153
- checked: boolean // New checked state
154
- }
155
- ```
156
-
157
- **Radio Event Detail:**
158
- ```typescript
159
- {
160
- type: "radio",
161
- name: string, // Name of the radio group
162
- value: string // Selected value
163
- }
164
- ```
165
-
166
- **Usage Example:**
167
- ```javascript
168
- const menubar = document.querySelector('rel-menubar');
169
- menubar.addEventListener('rel-menubar-change', (event) => {
170
- const { type, label, checked, name, value } = event.detail;
171
-
172
- if (type === 'checkbox') {
173
- console.log(`Checkbox "${label}" is now ${checked ? 'checked' : 'unchecked'}`);
174
- } else if (type === 'radio') {
175
- console.log(`Radio group "${name}" selected: ${value}`);
176
- }
177
- });
178
- ```
179
-
180
- ## Keyboard Navigation
181
-
182
- The menubar provides comprehensive keyboard support:
183
-
184
- | Key | Context | Action |
185
- |-----|---------|--------|
186
- | `Tab` / `Shift+Tab` | Menubar | Focus menubar triggers |
187
- | `ArrowLeft` / `ArrowRight` | Menubar triggers | Navigate between menu triggers |
188
- | `Enter` / `Space` | Focused trigger | Open the menu |
189
- | `ArrowDown` | Open menu | Move to first item or next item |
190
- | `ArrowUp` | Open menu | Move to previous item |
191
- | `ArrowRight` | Submenu item | Open submenu |
192
- | `ArrowLeft` | Open submenu | Close submenu and return to parent |
193
- | `Escape` | Open menu | Close menu and return focus to trigger |
194
- | `Enter` / `Space` | Menu item | Activate item (click, toggle checkbox, select radio) |
195
-
196
- ## Interaction Behavior
197
-
198
- ### Opening/Closing
199
- - Click a trigger to open its menu
200
- - Click outside to close all menus
201
- - When a menu is open, clicking another trigger switches to it
202
- - When a menu is open, hovering another trigger switches to it
203
-
204
- ### Submenus
205
- - Click or hover a submenu item to open its submenu
206
- - Submenu appears to the right of the parent menu
207
- - ArrowRight/ArrowLeft navigate in/out of submenus
208
-
209
- ### State Management
210
- - Checkbox state is maintained in the DOM
211
- - Radio group value is stored on the `data-radio-group` element
212
- - Selected radio items receive `data-checked` attribute
213
-
214
- ## Accessibility
215
-
216
- - Proper ARIA roles and keyboard navigation
217
- - Focus management with visual focus indicators
218
- - Screen reader friendly with semantic HTML
219
- - Disabled items are properly marked and non-interactive
220
- - All interactive elements are keyboard accessible
221
-
222
- ## Styling Tokens
223
-
224
- The component uses design tokens from the Reliability Design System:
225
-
226
- ### Colors
227
- - `--rel-bg-surface-elevated` - Menubar background
228
- - `--rel-bg-neutral-elevated-1` - Trigger and item hover state
229
- - `--rel-border-default` - Borders
230
- - `--rel-border-default` - Separators
231
- - `--rel-text-label` - Text color
232
- - `--rel-bg-surface` - Panel background
233
- - `--rel-bg-info` - Focus outline and radio selected state
234
-
235
- ### Typography
236
- - `--rel-fonts-font-family` - Font family (Poppins)
237
- - `--rel-body-sm-regular-font-size` - Default text size
238
- - `--rel-body-xs-regular-font-size` - Shortcut text size
239
- - `--rel-body-sm-regular-line-height` - Line height
240
-
241
- ### Spacing
242
- - `--rel-spacing-3xs` (2px) - Menubar gap and panel padding
243
- - `--rel-spacing-2xs` (4px) - Trigger padding vertical
244
- - `--rel-spacing-xs` (8px) - Item padding vertical
245
- - `--rel-spacing-sm` (12px) - Trigger and item horizontal padding
246
- - `--rel-spacing-md` (16px) - Item padding and radio offset
247
-
248
- ### Borders
249
- - `--rel-stroke-sm` (1px) - Border width
250
- - `--rel-stroke-md` (1.5px) - Radio border
251
- - `--rel-border-radius-xs` (2px) - Trigger border radius
252
- - `--rel-border-radius-sm` (8px) - Panel border radius
253
-
254
- ### Shadows
255
- - `--rel-shadows-shadow-300` - Panel drop shadow
256
-
257
- ### Z-Index
258
- - Menu panels: `z-index: 1000`
259
- - Submenu panels: `z-index: 1001`
260
-
261
- ## Browser Support
262
-
263
- Compatible with all modern browsers that support:
264
- - Web Components (Custom Elements v1)
265
- - Shadow DOM
266
- - ES2020+ features
267
-
268
- ## Framework Integration
269
-
270
- Works seamlessly with:
271
- - Vanilla JavaScript
272
- - Angular
273
- - React (via wrapper)
274
- - Vue
275
- - Any framework that supports Web Components
276
-
277
- ## Complete Example
278
-
279
- ```html
280
- <rel-menubar id="app-menubar">
281
- <rel-menubar-menu label="File">
282
- <button data-item data-shortcut="Ctrl+N">New Tab</button>
283
- <button data-item data-shortcut="Ctrl+Shift+N">New Window</button>
284
- <div data-separator></div>
285
- <div data-submenu label="Share">
286
- <button data-item>Email link</button>
287
- <button data-item>Messages</button>
288
- <button data-item>Notes</button>
289
- </div>
290
- <div data-separator></div>
291
- <button data-item>Close</button>
292
- </rel-menubar-menu>
293
-
294
- <rel-menubar-menu label="Edit">
295
- <button data-item data-shortcut="Ctrl+Z">Undo</button>
296
- <button data-item data-shortcut="Ctrl+Y">Redo</button>
297
- <div data-separator></div>
298
- <button data-item data-shortcut="Ctrl+X">Cut</button>
299
- <button data-item data-shortcut="Ctrl+C">Copy</button>
300
- <button data-item data-shortcut="Ctrl+V">Paste</button>
301
- </rel-menubar-menu>
302
-
303
- <rel-menubar-menu label="View">
304
- <button data-item>Zoom In</button>
305
- <button data-item>Zoom Out</button>
306
- <div data-separator></div>
307
- <label data-checkbox>
308
- <input type="checkbox" />
309
- Always Show Bookmarks Bar
310
- </label>
311
- <label data-checkbox>
312
- <input type="checkbox" checked />
313
- Always Show Full URLs
314
- </label>
315
- <div data-separator></div>
316
- <div data-radio-group name="profile" value="andy">
317
- <button data-radio value="andy">Andy</button>
318
- <button data-radio value="benoit">Benoit</button>
319
- <button data-radio value="luis">Luis</button>
320
- </div>
321
- </rel-menubar-menu>
322
- </rel-menubar>
323
-
324
- <script>
325
- document.getElementById('app-menubar').addEventListener('rel-menubar-change', (e) => {
326
- console.log('Menubar change:', e.detail);
327
- });
328
- </script>
329
- ```
1
+ # rel-menubar
2
+
3
+ `<rel-menubar>` is a horizontal application menubar (`role="menubar"`) in the style of a desktop app's File / Edit / View strip. Each child `<rel-menubar-menu label="…">` becomes a trigger button, and that menu's light-DOM children — `data-item` buttons, `data-separator` rules, `data-submenu` groups, `data-checkbox` labels and `data-radio-group` blocks — are read by the menubar and rendered into a fixed-position dropdown panel with full arrow-key navigation, optional bound keyboard shortcuts and `rel-menubar-select` / `rel-menubar-change` events. Use it for dense, command-style navigation in tools and admin surfaces. For one dropdown hanging off a single button use `rel-menu`; for site navigation with links use the Navbar recipe (`/docs/recipes/navbar`).
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <rel-menubar>
9
+ <rel-menubar-menu label="File">
10
+ <button data-item data-shortcut="Ctrl+N">New Tab</button>
11
+ <button data-item data-shortcut="Ctrl+Shift+N">New Window</button>
12
+ <div data-separator></div>
13
+ <button data-item disabled>Close</button>
14
+ </rel-menubar-menu>
15
+
16
+ <rel-menubar-menu label="Edit">
17
+ <button data-item data-shortcut="Ctrl+Z">Undo</button>
18
+ <button data-item data-shortcut="Ctrl+Y">Redo</button>
19
+ <div data-separator></div>
20
+ <button data-item data-shortcut="Ctrl+X">Cut</button>
21
+ <button data-item data-shortcut="Ctrl+C">Copy</button>
22
+ <button data-item data-shortcut="Ctrl+V">Paste</button>
23
+ </rel-menubar-menu>
24
+ </rel-menubar>
25
+ ```
26
+
27
+ ### Width mode and disabled menus
28
+
29
+ ```html
30
+ <!-- type="fit" (default) hugs its triggers; type="fixed" spans its container -->
31
+ <rel-menubar type="fixed">
32
+ <rel-menubar-menu label="File">
33
+ <button data-item>New Tab</button>
34
+ </rel-menubar-menu>
35
+ <rel-menubar-menu label="Edit">
36
+ <button data-item>Undo</button>
37
+ </rel-menubar-menu>
38
+ <!-- a disabled menu keeps its trigger visible and focusable but never opens -->
39
+ <rel-menubar-menu label="View" disabled>
40
+ <button data-item>Zoom In</button>
41
+ </rel-menubar-menu>
42
+ </rel-menubar>
43
+ ```
44
+
45
+ ### Submenus, checkbox items and radio groups
46
+
47
+ ```html
48
+ <rel-menubar>
49
+ <rel-menubar-menu label="File">
50
+ <button data-item>New Tab</button>
51
+ <div data-separator></div>
52
+ <div data-submenu label="Share">
53
+ <button data-item value="email">Email link</button>
54
+ <button data-item value="messages">Messages</button>
55
+ <button data-item value="notes">Notes</button>
56
+ </div>
57
+ </rel-menubar-menu>
58
+
59
+ <rel-menubar-menu label="View">
60
+ <label data-checkbox>
61
+ <input type="checkbox" />
62
+ Always Show Bookmarks Bar
63
+ </label>
64
+ <label data-checkbox>
65
+ <input type="checkbox" checked />
66
+ Always Show Full URLs
67
+ </label>
68
+ <div data-separator></div>
69
+ <div data-radio-group name="profile" value="andy">
70
+ <button data-radio value="andy">Andy</button>
71
+ <button data-radio value="benoit">Benoit</button>
72
+ <button data-radio value="luis">Luis</button>
73
+ </div>
74
+ </rel-menubar-menu>
75
+ </rel-menubar>
76
+ ```
77
+
78
+ ### Bound shortcuts and events
79
+
80
+ ```html
81
+ <rel-menubar id="app-menubar" bind-shortcuts>
82
+ <rel-menubar-menu label="Edit">
83
+ <button data-item value="undo" data-shortcut="Mod+Z">Undo</button>
84
+ <button data-item value="redo" data-shortcut="Mod+Shift+Z">Redo</button>
85
+ </rel-menubar-menu>
86
+ </rel-menubar>
87
+
88
+ <script>
89
+ const bar = document.getElementById('app-menubar');
90
+ // { label: "Undo", value: "undo", shortcut: "Mod+Z" }
91
+ bar.addEventListener('rel-menubar-select', (e) => console.log('select', e.detail));
92
+ // { type: "checkbox", label, checked } | { type: "radio", name, value }
93
+ bar.addEventListener('rel-menubar-change', (e) => console.log('change', e.detail));
94
+ </script>
95
+ ```
96
+
97
+ ### Authoring items
98
+
99
+ Items are plain HTML placed inside a `<rel-menubar-menu>`; the menubar recognises them by data attribute and renders its own copy in the panel.
100
+
101
+ | Attribute | Put it on | What it becomes |
102
+ | --- | --- | --- |
103
+ | `data-item` | `<button>` | A `role="menuitem"` row. Its text content is the label; `value` (optional) and `data-shortcut` are echoed in `rel-menubar-select`. A native `disabled` attribute renders the row `aria-disabled` and skips it for clicks and bound shortcuts. |
104
+ | `data-shortcut` | a `data-item` button | Shortcut text shown right-aligned in the row, exactly as written. With `bind-shortcuts` it is also matched against keydowns: `+`-joined tokens, case-insensitive, `Mod` = Cmd on Apple / Ctrl elsewhere, plus `Ctrl`, `Alt`, `Shift`, `Meta`. |
105
+ | `data-separator` | `<div>` | A `role="separator"` rule. |
106
+ | `data-submenu` + `label` | `<div>` wrapping `data-item` buttons | A submenu trigger row (`aria-haspopup="menu"`) that opens a nested panel to the right on hover, click, Enter or ArrowRight. |
107
+ | `data-checkbox` | `<label>` containing `<input type="checkbox">` | A `rel-checkbox` row. The label text is the element's own text nodes (or a `label` attribute); state lives on the wrapped `<input>`. |
108
+ | `data-radio-group` + `name` + `value` | `<div>` wrapping `data-radio` buttons | A `rel-radio` group. `value` on the wrapper is the current selection and is rewritten on change; the chosen `data-radio` also gets `data-checked="true"`. |
109
+ | `data-radio` + `value` | `<button>` inside a `data-radio-group` | One option; text content is its label. |
110
+
111
+ <!-- readme-gen:start -->
112
+
113
+ <!-- Generated from rel-menubar.ts, rel-menubar-menu.ts — do not edit; run readme-generate.mjs -->
114
+
115
+ ## Elements
116
+
117
+ | Element | Class | Source |
118
+ | --- | --- | --- |
119
+ | `<rel-menubar>` | `RelMenubar` | `rel-menubar.ts` |
120
+ | `<rel-menubar-menu>` | `RelMenubarMenu` | `rel-menubar-menu.ts` |
121
+
122
+ ## API
123
+
124
+ ### `<rel-menubar>`
125
+
126
+ #### Attributes / Properties
127
+
128
+ | Property | Attribute | Type | Default | Description |
129
+ | --- | --- | --- | --- | --- |
130
+ | `bindShortcuts` | `bind-shortcuts` | `boolean` | `false` | Opt-in: actually bind the keys declared via `data-shortcut` on items (e.g. `data-shortcut="Ctrl+Z"`) instead of only displaying them; a "Mod" token means Cmd on Apple platforms and Ctrl elsewhere, and keystrokes that originate in inputs, textareas or contenteditable regions are ignored. |
131
+ | `type` | `type` | `"fixed" \| "fit"` | `"fit"` | Width mode (Figma "Menu Bar" Type, 8699:4): `fit` sizes the bar to its triggers, `fixed` stretches it across its container (override the stretched width with `--rel-menubar-width`). Added in 1.4.8; the default stays `fit`, which is how the bar has always rendered. Reflected. |
132
+
133
+ ### Events
134
+
135
+ | Event | Detail | Bubbles / composed | Description |
136
+ | --- | --- | --- | --- |
137
+ | `rel-menubar-change` | `detail` | bubbles / composed | Fired when a `data-checkbox` item is toggled or a `data-radio` option is picked. Detail: `{ type: "checkbox", label, checked }` or `{ type: "radio", name, value }`. |
138
+ | `rel-menubar-select` | `{ label: item.textContent?.trim() ?? "", value: item.getAttribute("value") ?? undefined, shortcut: item.getAttribute("data-shortcut") ?? undefined, }` | bubbles / composed | Fired when a regular `data-item` (in a panel or a submenu) is activated by click, Enter/Space or a bound shortcut. Detail: `{ label: string, value?: string, shortcut?: string }` taken from the item's text, `value` and `data-shortcut` attributes. |
139
+
140
+ ### Slots
141
+
142
+ | Slot | Description |
143
+ | --- | --- |
144
+ | — | This element has no slots. |
145
+
146
+ ### CSS Parts
147
+
148
+ | Part | Description |
149
+ | --- | --- |
150
+ | — | None exposed. |
151
+
152
+ ### `<rel-menubar-menu>`
153
+
154
+ #### Attributes / Properties
155
+
156
+ | Property | Attribute | Type | Default | Description |
157
+ | --- | --- | --- | --- | --- |
158
+ | `label` | `label` | `string` | `""` | Text of the trigger button the parent menubar renders for this menu. |
159
+ | `disabled` | `disabled` | `boolean` | `false` | Renders this menu's trigger in the Figma State=Disabled style and stops it opening by pointer, keyboard or hover-switch. The trigger stays in the tab order and reachable with the arrow keys (`aria-disabled`, not the native `disabled` attribute), matching how disabled `data-item` rows behave. Reflected. |
160
+
161
+ ### Events
162
+
163
+ | Event | Detail | Bubbles / composed | Description |
164
+ | --- | --- | --- | --- |
165
+ | — | — | — | This element emits no custom events. |
166
+
167
+ ### Slots
168
+
169
+ | Slot | Description |
170
+ | --- | --- |
171
+ | — | This element has no slots. |
172
+
173
+ ### CSS Parts
174
+
175
+ | Part | Description |
176
+ | --- | --- |
177
+ | — | None exposed. |
178
+
179
+ <!-- readme-gen:end -->
180
+
181
+ ## Accessibility
182
+
183
+ - Roles follow the APG menubar pattern: the strip is `role="menubar"`; each trigger is a `<button role="menuitem" aria-haspopup="menu" aria-expanded="true|false">`; each dropdown is a `role="menu"` panel with `tabindex="-1"`; rows are `role="menuitem"` (disabled ones add `aria-disabled="true"`), separators are `role="separator"`, and a submenu trigger row carries `aria-haspopup="menu"` / `aria-expanded` with its own nested `role="menu"` panel.
184
+ - Focus model: the triggers are real buttons in the tab order. When a menu opens from the keyboard, DOM focus moves to the panel itself and the highlighted row is exposed through `aria-activedescendant` (row ids are generated per menubar instance), so arrow keys move a virtual focus rather than DOM focus. `Escape` closes everything and returns DOM focus to the trigger that owned the menu.
185
+ - Checkbox items render as `rel-checkbox` and radio groups as `rel-radio` inside the panel, so those rows carry the native checkbox / radiogroup semantics of those components.
186
+ - There is no type-ahead and no wrap-around: arrow keys stop at the first / last trigger or row.
187
+ - Bound shortcuts (`bind-shortcuts`) listen on `document`, skip events whose `defaultPrevented` is already set, skip keystrokes that start in an input, textarea, select or contenteditable, and call `preventDefault()` on a match.
188
+
189
+ | Key | Where | Action |
190
+ | --- | --- | --- |
191
+ | `Tab` / `Shift+Tab` | anywhere | Native focus movement between the trigger buttons (and out of the menubar). |
192
+ | `ArrowRight` / `ArrowLeft` | trigger | Move focus to the next / previous trigger (does not open it). |
193
+ | `Enter` / `Space` / `ArrowDown` | trigger | Open that menu, focus the panel and highlight the first item. |
194
+ | `Enter` / `Space` / `ArrowDown` | trigger of a `disabled` menu | Nothing — the trigger is reachable but never opens. |
195
+ | `Escape` | trigger (menu open) | Close all menus and keep focus on the trigger. |
196
+ | `ArrowDown` / `ArrowUp` | open panel | Highlight the next / previous item (clamped, no wrap). |
197
+ | `Home` / `End` | open panel | Highlight the first / last item. |
198
+ | `ArrowRight` | open panel, on a submenu row | Open the submenu and highlight its first item. |
199
+ | `Enter` / `Space` | open panel | Activate the highlighted row: fire `rel-menubar-select` and close, toggle a checkbox, pick a radio option, or open a submenu. |
200
+ | `Escape` | open panel | Close all menus and return focus to the trigger. |
201
+ | `ArrowDown` / `ArrowUp` / `Home` / `End` | open submenu | Move the highlight inside the submenu. |
202
+ | `ArrowLeft` / `Escape` | open submenu | Close only the submenu; the parent panel stays open and focused. |
203
+ | `Enter` / `Space` | open submenu | Activate the highlighted sub-item: fire `rel-menubar-select`, close everything, refocus the trigger. |
204
+
205
+ ## Notes / Edge Cases
206
+
207
+ - Both elements render into **light DOM** (`createRenderRoot()` returns the host): there are no slots, no `::part` hooks and no style encapsulation. The menubar injects its own `<style>` block; the `.menubar-trigger` / `.menubar-panel` / `.menu-item` class names are implementation details, not a styling contract.
208
+ - `<rel-menubar-menu>` is a hidden data holder (`display: none`) — it never renders its children itself. The menubar discovers menus once, when it connects; menus added or removed later are not picked up until the menubar is re-attached. Item lists inside a menu are re-read on each render, so item changes show up the next time a panel opens.
209
+ - Item content is flattened: a `data-item` row renders the button's `textContent` only, so markup inside the button (icons, `<rel-kbd>` chips) is not reproduced. Use `data-shortcut` for the shortcut hint — it is displayed verbatim, so `Mod+Z` is shown literally as "Mod+Z"; write `Ctrl+Z` if you want that text and only need Ctrl.
210
+ - Panels are `position: fixed` (z-index 1000, submenus 1001), placed flush under the trigger / against the right edge of the submenu row, and repositioned on scroll. They are not moved into the top layer, so a `rel-modal` or other top-layer surface can cover them.
211
+ - Panels are a fixed 300px wide, matching the Figma Menu component the bar is paired with; override with `--rel-menubar-panel-width`. There is no viewport clamping, so a panel opened near the right edge can overflow.
212
+ - The bar follows Figma's Menu Bar geometry: 40px tall triggers (`spacing/xs` × `spacing/md` padding on a `body/lg` label) on a `bg/fill/neutral/default` surface with `border-radius/sm` and no border. The trigger whose menu is open takes the hover overlay plus a medium-weight label, which widens it by a pixel or two — that weight shift is in the Figma spec, not an artefact.
213
+ - A `disabled` `<rel-menubar-menu>` renders its trigger in the disabled tone and refuses to open by click, hover-switch, Enter/Space/ArrowDown or a bound shortcut. It uses `aria-disabled`, not the native `disabled` attribute, so the trigger stays in the tab order — the same model the disabled `data-item` rows use.
214
+ - With a menu already open the bar is in hover-switch mode: moving the pointer onto another trigger opens that menu, so a *click* on it arrives when it is already open and toggles it shut. Switch menus by hovering, or click twice.
215
+ - Hover-switching between menus is armed only after a click has opened one; hovering triggers on a closed menubar does nothing. Clicking outside (checked via `composedPath`, so it works inside shadow roots) closes everything.
216
+ - Disabled `data-item` buttons ignore pointer clicks and bound shortcuts but are still reachable with the arrow keys.
217
+ - `rel-menubar-select` fires only for regular `data-item` rows (panel or submenu); checkbox and radio rows fire `rel-menubar-change` instead. Both events bubble and are composed.
218
+ - Only one submenu can be open at a time, and submenus nest one level deep (a `data-submenu` inside a `data-submenu` is not rendered).