@phcdevworks/spectre-components 1.12.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +240 -138
  2. package/dist/alert.cjs.map +1 -1
  3. package/dist/alert.d.cts +2 -2
  4. package/dist/alert.d.ts +2 -2
  5. package/dist/alert.js.map +1 -1
  6. package/dist/avatar.cjs.map +1 -1
  7. package/dist/avatar.d.cts +2 -2
  8. package/dist/avatar.d.ts +2 -2
  9. package/dist/avatar.js.map +1 -1
  10. package/dist/badge.cjs.map +1 -1
  11. package/dist/badge.d.cts +2 -2
  12. package/dist/badge.d.ts +2 -2
  13. package/dist/badge.js.map +1 -1
  14. package/dist/button.cjs +24 -0
  15. package/dist/button.cjs.map +1 -1
  16. package/dist/button.d.cts +21 -3
  17. package/dist/button.d.ts +21 -3
  18. package/dist/button.js +24 -0
  19. package/dist/button.js.map +1 -1
  20. package/dist/card.cjs.map +1 -1
  21. package/dist/card.d.cts +2 -2
  22. package/dist/card.d.ts +2 -2
  23. package/dist/card.js.map +1 -1
  24. package/dist/container.cjs +17 -1
  25. package/dist/container.cjs.map +1 -1
  26. package/dist/container.d.cts +9 -2
  27. package/dist/container.d.ts +9 -2
  28. package/dist/container.js +17 -1
  29. package/dist/container.js.map +1 -1
  30. package/dist/dropdown.cjs +10 -1
  31. package/dist/dropdown.cjs.map +1 -1
  32. package/dist/dropdown.d.cts +8 -2
  33. package/dist/dropdown.d.ts +8 -2
  34. package/dist/dropdown.js +10 -1
  35. package/dist/dropdown.js.map +1 -1
  36. package/dist/footer.cjs +18 -2
  37. package/dist/footer.cjs.map +1 -1
  38. package/dist/footer.d.cts +7 -0
  39. package/dist/footer.d.ts +7 -0
  40. package/dist/footer.js +18 -2
  41. package/dist/footer.js.map +1 -1
  42. package/dist/{form-JrKDonG4.d.cts → form-BGQjgJrL.d.cts} +10 -1
  43. package/dist/{form-JrKDonG4.d.ts → form-BGQjgJrL.d.ts} +10 -1
  44. package/dist/grid.cjs +53 -3
  45. package/dist/grid.cjs.map +1 -1
  46. package/dist/grid.d.cts +14 -2
  47. package/dist/grid.d.ts +14 -2
  48. package/dist/grid.js +53 -3
  49. package/dist/grid.js.map +1 -1
  50. package/dist/icon-box.cjs.map +1 -1
  51. package/dist/icon-box.d.cts +2 -2
  52. package/dist/icon-box.d.ts +2 -2
  53. package/dist/icon-box.js.map +1 -1
  54. package/dist/index.cjs +298 -22
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.d.cts +3 -2
  57. package/dist/index.d.ts +3 -2
  58. package/dist/index.js +298 -24
  59. package/dist/index.js.map +1 -1
  60. package/dist/input.cjs.map +1 -1
  61. package/dist/input.d.cts +2 -2
  62. package/dist/input.d.ts +2 -2
  63. package/dist/input.js.map +1 -1
  64. package/dist/nav-item.cjs +7 -1
  65. package/dist/nav-item.cjs.map +1 -1
  66. package/dist/nav-item.d.cts +7 -1
  67. package/dist/nav-item.d.ts +7 -1
  68. package/dist/nav-item.js +7 -1
  69. package/dist/nav-item.js.map +1 -1
  70. package/dist/nav.cjs +17 -1
  71. package/dist/nav.cjs.map +1 -1
  72. package/dist/nav.d.cts +7 -0
  73. package/dist/nav.d.ts +7 -0
  74. package/dist/nav.js +17 -1
  75. package/dist/nav.js.map +1 -1
  76. package/dist/rating.cjs.map +1 -1
  77. package/dist/rating.d.cts +2 -2
  78. package/dist/rating.d.ts +2 -2
  79. package/dist/rating.js.map +1 -1
  80. package/dist/section.cjs +22 -1
  81. package/dist/section.cjs.map +1 -1
  82. package/dist/section.d.cts +9 -0
  83. package/dist/section.d.ts +9 -0
  84. package/dist/section.js +22 -1
  85. package/dist/section.js.map +1 -1
  86. package/dist/select.cjs.map +1 -1
  87. package/dist/select.d.cts +1 -1
  88. package/dist/select.d.ts +1 -1
  89. package/dist/select.js.map +1 -1
  90. package/dist/sidebar-toggle.cjs +465 -0
  91. package/dist/sidebar-toggle.cjs.map +1 -0
  92. package/dist/sidebar-toggle.d.cts +44 -0
  93. package/dist/sidebar-toggle.d.ts +44 -0
  94. package/dist/sidebar-toggle.js +462 -0
  95. package/dist/sidebar-toggle.js.map +1 -0
  96. package/dist/sidebar.cjs +15 -10
  97. package/dist/sidebar.cjs.map +1 -1
  98. package/dist/sidebar.d.cts +7 -0
  99. package/dist/sidebar.d.ts +7 -0
  100. package/dist/sidebar.js +15 -10
  101. package/dist/sidebar.js.map +1 -1
  102. package/dist/spinner.cjs.map +1 -1
  103. package/dist/spinner.d.cts +2 -2
  104. package/dist/spinner.d.ts +2 -2
  105. package/dist/spinner.js.map +1 -1
  106. package/dist/stack.cjs +18 -2
  107. package/dist/stack.cjs.map +1 -1
  108. package/dist/stack.d.cts +9 -2
  109. package/dist/stack.d.ts +9 -2
  110. package/dist/stack.js +18 -2
  111. package/dist/stack.js.map +1 -1
  112. package/dist/tag.cjs.map +1 -1
  113. package/dist/tag.d.cts +2 -2
  114. package/dist/tag.d.ts +2 -2
  115. package/dist/tag.js.map +1 -1
  116. package/dist/testimonial.cjs.map +1 -1
  117. package/dist/testimonial.d.cts +2 -2
  118. package/dist/testimonial.d.ts +2 -2
  119. package/dist/testimonial.js.map +1 -1
  120. package/dist/text.cjs +16 -0
  121. package/dist/text.cjs.map +1 -1
  122. package/dist/text.d.cts +8 -2
  123. package/dist/text.d.ts +8 -2
  124. package/dist/text.js +16 -0
  125. package/dist/text.js.map +1 -1
  126. package/dist/textarea.cjs.map +1 -1
  127. package/dist/textarea.d.cts +1 -1
  128. package/dist/textarea.d.ts +1 -1
  129. package/dist/textarea.js.map +1 -1
  130. package/dist/toast.cjs.map +1 -1
  131. package/dist/toast.d.cts +2 -2
  132. package/dist/toast.d.ts +2 -2
  133. package/dist/toast.js.map +1 -1
  134. package/dist/tooltip.cjs.map +1 -1
  135. package/dist/tooltip.d.cts +2 -2
  136. package/dist/tooltip.d.ts +2 -2
  137. package/dist/tooltip.js.map +1 -1
  138. package/package.json +21 -16
package/README.md CHANGED
@@ -4,10 +4,10 @@
4
4
  Spectre system. It implements Spectre's design contracts as reusable,
5
5
  accessible, framework-agnostic web components.
6
6
 
7
- Maintained by [PHCDevworks](https://go.phcdev.co). It draws on Spectre's
8
- token and styling contracts to ship drop-in UI primitives, so applications
9
- that need working components — rather than raw CSS or recipes to assemble
10
- themselves — can consume Spectre without a framework-specific adapter.
7
+ Maintained by [PHCDevworks](https://go.phcdev.co). It draws on Spectre's token
8
+ and styling contracts to ship drop-in UI primitives, so applications that need
9
+ working components — rather than raw CSS or recipes to assemble themselves — can
10
+ consume Spectre without a framework-specific adapter.
11
11
 
12
12
  ## Repository Snapshot
13
13
 
@@ -16,7 +16,7 @@ themselves — can consume Spectre without a framework-specific adapter.
16
16
  | Project team | `project-design` |
17
17
  | Repository role | Spectre L3a Lit web component layer |
18
18
  | Package/artifact | `@phcdevworks/spectre-components` |
19
- | Current version/status | 1.12.0 |
19
+ | Current version/status | 1.15.0 |
20
20
 
21
21
  ## Standard Workflow
22
22
 
@@ -327,32 +327,38 @@ design-system-level decision.
327
327
 
328
328
  ### sp-button
329
329
 
330
- Renders a `<button>` with Spectre variant, size, loading, and pill support.
330
+ Renders a `<button>` with Spectre variant, size, loading, and pill support. Set
331
+ `href` to render a native `<a>` instead, styled with the same classes — useful
332
+ when the button needs to navigate rather than submit/act.
331
333
 
332
334
  **Attributes**
333
335
 
334
- | Attribute | Type | Default | Description |
335
- | ------------------ | --------------------------------------------------------------------- | --------- | -------------------------------------------------------- |
336
- | `variant` | `primary \| secondary \| ghost \| danger \| success \| cta \| accent` | `primary` | Visual style |
337
- | `size` | `sm \| md \| lg` | `md` | Control size |
338
- | `type` | `button \| submit \| reset` | `button` | Native button type |
339
- | `label` | string | — | Text label (overridden by content projection) |
340
- | `loading` | boolean | `false` | Busy state — disables the button and shows loading label |
341
- | `loading-label` | string | `Loading` | Accessible text shown during loading |
342
- | `disabled` | boolean | `false` | Disables the button |
343
- | `full-width` | boolean | `false` | Spans full container width |
344
- | `pill` | boolean | `false` | Pill / fully-rounded corners |
345
- | `name` | string | — | Form field name |
346
- | `value` | string | `''` | Submitted value |
347
- | `form` | string | — | Associates with a form by ID |
348
- | `autofocus` | boolean | `false` | Autofocus on page load |
349
- | `id` | string | — | Forwarded to the native `<button>` |
350
- | `title` | string | — | Forwarded to the native `<button>` |
351
- | `aria-label` | string | — | Forwarded to the native `<button>` |
352
- | `aria-labelledby` | string | — | Forwarded to the native `<button>` |
353
- | `aria-describedby` | string | — | Forwarded to the native `<button>` |
354
-
355
- **Events** — native button events bubble normally (`click`, `focus`, `blur`).
336
+ | Attribute | Type | Default | Description |
337
+ | ------------------ | --------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- |
338
+ | `variant` | `primary \| secondary \| ghost \| danger \| success \| cta \| accent` | `primary` | Visual style |
339
+ | `size` | `sm \| md \| lg` | `md` | Control size |
340
+ | `type` | `button \| submit \| reset` | `button` | Native button type (ignored when rendered as a link) |
341
+ | `href` | string | — | Renders `<a href>` instead of `<button>` (unless `disabled`/`loading`) |
342
+ | `target` | `_blank \| _self \| _parent \| _top` | — | Forwarded to the native `<a>` when `href` is set |
343
+ | `rel` | string | — | Forwarded to the native `<a>` when `href` is set |
344
+ | `label` | string | — | Text label (overridden by content projection) |
345
+ | `loading` | boolean | `false` | Busy state — disables the button/link and shows loading label |
346
+ | `loading-label` | string | `Loading` | Accessible text shown during loading |
347
+ | `disabled` | boolean | `false` | Disables the button; if `href` is also set, still renders `<button disabled>` |
348
+ | `full-width` | boolean | `false` | Spans full container width |
349
+ | `pill` | boolean | `false` | Pill / fully-rounded corners |
350
+ | `name` | string | — | Form field name |
351
+ | `value` | string | `''` | Submitted value |
352
+ | `form` | string | — | Associates with a form by ID |
353
+ | `autofocus` | boolean | `false` | Autofocus on page load |
354
+ | `id` | string | — | Forwarded to the native element |
355
+ | `title` | string | — | Forwarded to the native element |
356
+ | `aria-label` | string | — | Forwarded to the native element |
357
+ | `aria-labelledby` | string | — | Forwarded to the native element |
358
+ | `aria-describedby` | string | — | Forwarded to the native element |
359
+
360
+ **Events** — native button/link events bubble normally (`click`, `focus`,
361
+ `blur`).
356
362
 
357
363
  **Content projection** — place children inside `<sp-button>` to use them as
358
364
  button content instead of the `label` property:
@@ -364,7 +370,16 @@ button content instead of the `label` property:
364
370
  </sp-button>
365
371
  ```
366
372
 
367
- **Internal target** — `[data-sp-button-native]` selects the native `<button>`.
373
+ **Link mode:**
374
+
375
+ ```html
376
+ <sp-button variant="secondary" href="/pricing" target="_blank" rel="noopener">
377
+ View pricing
378
+ </sp-button>
379
+ ```
380
+
381
+ **Internal target** — `[data-sp-button-native]` selects the native `<button>` or
382
+ `<a>`.
368
383
 
369
384
  ---
370
385
 
@@ -797,16 +812,41 @@ price, feature list, call-to-action, etc.).
797
812
 
798
813
  ---
799
814
 
815
+ ### Layout components
816
+
817
+ `sp-container`, `sp-grid`, `sp-section`, `sp-stack`, `sp-footer`, and `sp-nav`
818
+ share two contracts:
819
+
820
+ - **Host display** — the host element defaults to `display: block` (set via
821
+ inline style in `connectedCallback`, so a consumer's own
822
+ `style="display: ..."` always wins) instead of the browser's default inline
823
+ custom-element box. This keeps backgrounds, margins, and full-width inner
824
+ content from being trapped inside an inline box.
825
+ - **`inner-class`** — an `inner-class` attribute (`innerClass` JS property)
826
+ appends consumer-supplied Spectre utility classes to the native inner element
827
+ the component's recipe classes render on, without touching the host's own
828
+ `class` attribute. Host `class` and `inner-class` are distinct targets: host
829
+ `class` affects the custom-element box itself, `inner-class` affects the
830
+ styled element inside it. Only tokens matching `sp-*` (Spectre utility class
831
+ syntax) are applied; anything else is silently dropped.
832
+
833
+ ```html
834
+ <sp-stack class="my-host-hook" inner-class="sp-bg-primary-500 sp-p-8">
835
+ ...
836
+ </sp-stack>
837
+ ```
838
+
800
839
  ### sp-container
801
840
 
802
841
  Renders a `<div>` layout container backed by the Spectre container recipe.
803
842
 
804
843
  **Attributes**
805
844
 
806
- | Attribute | Type | Default | Description |
807
- | ------------------------- | ------- | ------- | --------------------------------- |
808
- | `max-width` | `prose` | — | Constrains content to a max width |
809
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<div>` |
845
+ | Attribute | Type | Default | Description |
846
+ | ------------------------- | ------- | ------- | ----------------------------------------------------- |
847
+ | `max-width` | `prose` | — | Constrains content to a max width |
848
+ | `inner-class` | string | — | Spectre utility classes applied to the native `<div>` |
849
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<div>` |
810
850
 
811
851
  **Content projection** — children become the container content.
812
852
 
@@ -820,11 +860,13 @@ Renders a `<div>` grid layout backed by the Spectre grid recipe.
820
860
 
821
861
  **Attributes**
822
862
 
823
- | Attribute | Type | Default | Description |
824
- | ------------------------- | ----------------------------- | ------- | ------------------------------- |
825
- | `columns` | `1 \| 2 \| 3 \| 4 \| 6 \| 12` | `1` | Number of grid columns |
826
- | `gap` | `sm \| md \| lg` | `md` | Gap between grid items |
827
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<div>` |
863
+ | Attribute | Type | Default | Description |
864
+ | ------------------------- | ------------------------------------------------------------ | ------- | ----------------------------------------------------------- |
865
+ | `columns` | `1 \| 2 \| 3 \| 4 \| 6 \| 12` | `1` | Number of grid columns |
866
+ | `gap` | `sm \| md \| lg` | `md` | Gap between grid items |
867
+ | `span` | `1-12 \| 'full'` or `{ base?, md?, lg? }` (JS property only) | — | Column span for a grid item, single value or per-breakpoint |
868
+ | `inner-class` | string | — | Spectre utility classes applied to the native `<div>` |
869
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<div>` |
828
870
 
829
871
  **Content projection** — children become grid items.
830
872
 
@@ -838,9 +880,10 @@ Renders a `<section>` layout wrapper backed by the Spectre section recipe.
838
880
 
839
881
  **Attributes**
840
882
 
841
- | Attribute | Type | Default | Description |
842
- | ------------------------- | ------ | ------- | ----------------------------------- |
843
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<section>` |
883
+ | Attribute | Type | Default | Description |
884
+ | ------------------------- | ------ | ------- | --------------------------------------------------------- |
885
+ | `inner-class` | string | — | Spectre utility classes applied to the native `<section>` |
886
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<section>` |
844
887
 
845
888
  **Content projection** — children become the section content.
846
889
 
@@ -854,12 +897,13 @@ Renders a `<div>` flex stack backed by the Spectre stack recipe.
854
897
 
855
898
  **Attributes**
856
899
 
857
- | Attribute | Type | Default | Description |
858
- | ------------------------- | ------------------------ | ---------- | ------------------------------------- |
859
- | `direction` | `vertical \| horizontal` | `vertical` | Stack axis |
860
- | `basis` | `sidebar` | — | Reserves sidebar-sized basis on items |
861
- | `align` | `center \| stretch` | `center` | Cross-axis alignment |
862
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<div>` |
900
+ | Attribute | Type | Default | Description |
901
+ | ------------------------- | ------------------------ | ---------- | ----------------------------------------------------- |
902
+ | `direction` | `vertical \| horizontal` | `vertical` | Stack axis |
903
+ | `basis` | `sidebar` | — | Reserves sidebar-sized basis on items |
904
+ | `align` | `center \| stretch` | `center` | Cross-axis alignment |
905
+ | `inner-class` | string | — | Spectre utility classes applied to the native `<div>` |
906
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<div>` |
863
907
 
864
908
  **Content projection** — children become stack items.
865
909
 
@@ -873,14 +917,15 @@ Renders a `<footer>` backed by the Spectre footer recipe.
873
917
 
874
918
  **Attributes**
875
919
 
876
- | Attribute | Type | Default | Description |
877
- | ------------------------- | ------- | ------- | ---------------------------------- |
878
- | `bordered` | boolean | `false` | Adds a top border |
879
- | `full-width` | boolean | `false` | Spans full container width |
880
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<footer>` |
920
+ | Attribute | Type | Default | Description |
921
+ | ------------------------- | ------- | ------- | -------------------------------------------------------- |
922
+ | `bordered` | boolean | `false` | Adds a top border |
923
+ | `full-width` | boolean | `false` | Spans full container width |
924
+ | `inner-class` | string | — | Spectre utility classes applied to the native `<footer>` |
925
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<footer>` |
881
926
 
882
- **Content projection** — children become the footer content (links, legal
883
- text, etc.).
927
+ **Content projection** — children become the footer content (links, legal text,
928
+ etc.).
884
929
 
885
930
  **Internal target** — `[data-sp-footer-native]` selects the native `<footer>`.
886
931
 
@@ -892,12 +937,13 @@ Renders a `<nav>` backed by the Spectre nav recipe.
892
937
 
893
938
  **Attributes**
894
939
 
895
- | Attribute | Type | Default | Description |
896
- | ------------------------- | ------- | ------- | ------------------------------- |
897
- | `bordered` | boolean | `false` | Adds a bottom border |
898
- | `sticky` | boolean | `false` | Sticks the nav to the viewport |
899
- | `full-width` | boolean | `false` | Spans full container width |
900
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<nav>` |
940
+ | Attribute | Type | Default | Description |
941
+ | ------------------------- | ------- | ------- | ----------------------------------------------------- |
942
+ | `bordered` | boolean | `false` | Adds a bottom border |
943
+ | `sticky` | boolean | `false` | Sticks the nav to the viewport |
944
+ | `full-width` | boolean | `false` | Spans full container width |
945
+ | `inner-class` | string | — | Spectre utility classes applied to the native `<nav>` |
946
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<nav>` |
901
947
 
902
948
  **Content projection** — children become the nav content (links, brand mark,
903
949
  etc.).
@@ -908,30 +954,31 @@ etc.).
908
954
 
909
955
  ### sp-nav-item
910
956
 
911
- Renders a nav link that can optionally become a dropdown trigger, backed by
912
- the same Spectre dropdown recipe as `sp-dropdown`. Place it inside `sp-nav`
957
+ Renders a nav link that can optionally become a dropdown trigger, backed by the
958
+ same Spectre dropdown recipe as `sp-dropdown`. Place it inside `sp-nav`
913
959
  alongside plain `<a>` links.
914
960
 
915
961
  **Attributes**
916
962
 
917
- | Attribute | Type | Default | Description |
918
- | ------------------------- | ------- | ---------------- | ------------------------------------------------------------------- |
919
- | `dropdown` | boolean | `false` | Renders a dropdown trigger + menu instead of a plain `<a>` |
920
- | `href` | string | — | Link target when `dropdown` is `false` |
921
- | `label` | string | — | Trigger/link text when no content is projected |
922
- | `open` | boolean | `false` | Open/closed menu state (dropdown mode only) |
923
- | `placement` | string | `'bottom-start'` | Menu position: `bottom-start`, `bottom-end`, `top-start`, `top-end` |
924
- | `id` / `title` / `aria-*` | string | — | Forwarded to the rendered `<a>` or trigger `<button>` |
925
-
926
- **Content projection** — in dropdown mode, children become the menu content;
927
- a child with `slot="trigger"` becomes the trigger content instead of `label`.
928
- Menu content can be a plain list of links or an `sp-grid` for a full mega-menu
963
+ | Attribute | Type | Default | Description |
964
+ | ------------------------- | ------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
965
+ | `dropdown` | boolean | `false` | Renders a dropdown trigger + menu instead of a plain `<a>` |
966
+ | `href` | string | — | Link target when `dropdown` is `false` |
967
+ | `label` | string | — | Trigger/link text when no content is projected |
968
+ | `mega` | boolean | `false` | Anchors the menu to the nearest positioned ancestor instead of the trigger, spanning its full width (dropdown mode only) |
969
+ | `open` | boolean | `false` | Open/closed menu state (dropdown mode only) |
970
+ | `placement` | string | `'bottom-start'` | Menu position: `bottom-start`, `bottom-end`, `top-start`, `top-end` |
971
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the rendered `<a>` or trigger `<button>` |
972
+
973
+ **Content projection** — in dropdown mode, children become the menu content; a
974
+ child with `slot="trigger"` becomes the trigger content instead of `label`. Menu
975
+ content can be a plain list of links or an `sp-grid` for a full mega-menu
929
976
  layout. In link mode, children become the link's content.
930
977
 
931
978
  **Events** — `sp-open` and `sp-close` (dropdown mode only), both `bubbles`.
932
979
 
933
- **Internal targets** — `[data-sp-nav-item-trigger]` selects the trigger
934
- button; `[data-sp-nav-item-menu]` selects the menu panel.
980
+ **Internal targets** — `[data-sp-nav-item-trigger]` selects the trigger button;
981
+ `[data-sp-nav-item-menu]` selects the menu panel.
935
982
 
936
983
  ```html
937
984
  <sp-nav>
@@ -943,9 +990,20 @@ button; `[data-sp-nav-item-menu]` selects the menu panel.
943
990
  <div>Column three</div>
944
991
  </sp-grid>
945
992
  </sp-nav-item>
993
+ <sp-nav-item dropdown mega label="Solutions">
994
+ <sp-grid columns="4" gap="lg">
995
+ <div>Column one</div>
996
+ <div>Column two</div>
997
+ <div>Column three</div>
998
+ <div>Column four</div>
999
+ </sp-grid>
1000
+ </sp-nav-item>
946
1001
  </sp-nav>
947
1002
  ```
948
1003
 
1004
+ `mega` requires a positioned ancestor to anchor against — `sp-nav` is a
1005
+ positioning context by default, so nesting inside it is sufficient.
1006
+
949
1007
  ---
950
1008
 
951
1009
  ### sp-sidebar
@@ -955,12 +1013,13 @@ Spectre sidebar recipe.
955
1013
 
956
1014
  **Attributes**
957
1015
 
958
- | Attribute | Type | Default | Description |
959
- | ------------------------- | ------- | ---------------- | -------------------------------------- |
960
- | `bordered` | boolean | `false` | Adds a trailing border |
961
- | `open` | boolean | `false` | Open/closed off-canvas state |
962
- | `toggle-label` | string | `Toggle sidebar` | Accessible label for the toggle button |
963
- | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<aside>` |
1016
+ | Attribute | Type | Default | Description |
1017
+ | ------------------------- | ------- | ---------------- | ------------------------------------------------------------------------------------- |
1018
+ | `bordered` | boolean | `false` | Adds a trailing border |
1019
+ | `hide-toggle` | boolean | `false` | Suppresses the built-in toggle button (e.g. when using `sp-sidebar-toggle` elsewhere) |
1020
+ | `open` | boolean | `false` | Open/closed off-canvas state |
1021
+ | `toggle-label` | string | `Toggle sidebar` | Accessible label for the built-in toggle button |
1022
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<aside>` |
964
1023
 
965
1024
  **Content projection** — children become the sidebar content (links, navigation
966
1025
  groups, etc.).
@@ -977,6 +1036,45 @@ hide the off-canvas panel and backdrop.
977
1036
 
978
1037
  ---
979
1038
 
1039
+ ### sp-sidebar-toggle
1040
+
1041
+ Renders a standalone trigger button that opens/closes a remote `sp-sidebar`,
1042
+ backed by the Spectre sidebar-toggle recipe. Use it to place a toggle somewhere
1043
+ other than inside the sidebar itself (a header, a nav bar) — pair it with
1044
+ `hide-toggle` on the target `sp-sidebar` to suppress that sidebar's own built-in
1045
+ toggle, or leave both in place to control the same sidebar from two triggers.
1046
+
1047
+ **Attributes**
1048
+
1049
+ | Attribute | Type | Default | Description |
1050
+ | ------------------------- | ------ | ---------------- | ------------------------------------------------------------------------------------------------ |
1051
+ | `for` | string | — | `id` of the target `sp-sidebar`'s native content (the id set on the `sp-sidebar` element itself) |
1052
+ | `label` | string | `Toggle sidebar` | Accessible label when no icon content is projected |
1053
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the native `<button>` |
1054
+
1055
+ **Content projection** — children become the button's icon content; falls back
1056
+ to a default `☰` glyph when empty.
1057
+
1058
+ **Behavior** — clicking the button toggles the target `sp-sidebar`'s `open`
1059
+ property and mirrors its own `aria-expanded` state, including staying in sync
1060
+ when the target is opened/closed by another trigger (its own built-in toggle,
1061
+ the backdrop, `Esc`, or a second `sp-sidebar-toggle`).
1062
+
1063
+ ```html
1064
+ <sp-nav>
1065
+ <sp-sidebar-toggle for="app-sidebar"></sp-sidebar-toggle>
1066
+ </sp-nav>
1067
+
1068
+ <sp-sidebar id="app-sidebar" hide-toggle>
1069
+ <a href="/dashboard">Dashboard</a>
1070
+ </sp-sidebar>
1071
+ ```
1072
+
1073
+ **Internal target** — `[data-sp-sidebar-toggle-native]` selects the native
1074
+ `<button>`.
1075
+
1076
+ ---
1077
+
980
1078
  ### sp-dropdown
981
1079
 
982
1080
  Renders a trigger button and a menu container, backed by the Spectre dropdown
@@ -984,13 +1082,14 @@ recipes.
984
1082
 
985
1083
  **Attributes**
986
1084
 
987
- | Attribute | Type | Default | Description |
988
- | ------------------------- | ---------------------------------------------------- | -------------- | ----------------------------------------------------------------------------- |
989
- | `open` | boolean | `false` | Open/closed menu state |
990
- | `placement` | `bottom-start \| bottom-end \| top-start \| top-end` | `bottom-start` | Menu position relative to trigger |
991
- | `full-width` | boolean | `false` | Spans full container width |
992
- | `trigger-label` | string | `Toggle menu` | Visible/accessible trigger text when no `slot="trigger"` content is projected |
993
- | `id` / `title` / `aria-*` | string | — | Forwarded to the trigger button |
1085
+ | Attribute | Type | Default | Description |
1086
+ | ------------------------- | ---------------------------------------------------- | -------------- | --------------------------------------------------------------------------------------------------- |
1087
+ | `open` | boolean | `false` | Open/closed menu state |
1088
+ | `placement` | `bottom-start \| bottom-end \| top-start \| top-end` | `bottom-start` | Menu position relative to trigger |
1089
+ | `full-width` | boolean | `false` | Spans full container width |
1090
+ | `mega` | boolean | `false` | Anchors the menu to the nearest positioned ancestor instead of the trigger, spanning its full width |
1091
+ | `trigger-label` | string | `Toggle menu` | Visible/accessible trigger text when no `slot="trigger"` content is projected |
1092
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the trigger button |
994
1093
 
995
1094
  **Content projection** — an element with `slot="trigger"` becomes the trigger
996
1095
  button content; all other children become the menu content.
@@ -1096,13 +1195,14 @@ switches with `level` while the recipe call and styling stay the same.
1096
1195
 
1097
1196
  **Attributes**
1098
1197
 
1099
- | Attribute | Type | Default | Description |
1100
- | ------------------------- | -------------------------------------------------------- | --------- | --------------------------------------- |
1101
- | `level` | `h1 \| h2 \| h3 \| h4 \| h5 \| h6 \| p \| span` | `p` | Rendered element tag |
1102
- | `size` | `xs \| sm \| md \| lg \| xl \| 2xl \| 3xl \| 4xl \| 5xl \| 6xl` | `md` | Text size scale |
1103
- | `variant` | `default \| muted \| subtle \| meta \| brand` | `default` | Text color role |
1104
- | `family` | `sans \| serif \| mono` | — | Optional font family override |
1105
- | `id` / `title` / `aria-*` | string | — | Forwarded to the rendered native element |
1198
+ | Attribute | Type | Default | Description |
1199
+ | ------------------------- | --------------------------------------------------------------- | --------- | ---------------------------------------- |
1200
+ | `level` | `h1 \| h2 \| h3 \| h4 \| h5 \| h6 \| p \| span` | `p` | Rendered element tag |
1201
+ | `size` | `xs \| sm \| md \| lg \| xl \| 2xl \| 3xl \| 4xl \| 5xl \| 6xl` | `md` | Text size scale |
1202
+ | `variant` | `default \| muted \| subtle \| meta \| brand` | `default` | Text color role |
1203
+ | `family` | `sans \| serif \| mono` | — | Optional font family override |
1204
+ | `transform` | `none \| uppercase \| lowercase \| capitalize` | — | Optional text transform |
1205
+ | `id` / `title` / `aria-*` | string | — | Forwarded to the rendered native element |
1106
1206
 
1107
1207
  **Content projection** — children become the text content.
1108
1208
 
@@ -1179,45 +1279,47 @@ defineSpectreComponents() // registers all sp-* elements
1179
1279
  **Interactive constants and types**: `spectreDropdownPlacements`,
1180
1280
  `spectreToastVariants`, `spectreTooltipPlacements`, `SpectreDropdownPlacement`,
1181
1281
  `SpectreToastVariant`, `SpectreTooltipPlacement`, `SpectreFooterProps`,
1182
- `SpectreNavProps`, `SpectreSidebarProps`, `SpectreDropdownProps`,
1183
- `SpectreModalProps`, `SpectreToastProps`, `SpectreTooltipProps`
1282
+ `SpectreNavProps`, `SpectreSidebarProps`, `SpectreSidebarToggleProps`,
1283
+ `SpectreDropdownProps`, `SpectreModalProps`, `SpectreToastProps`,
1284
+ `SpectreTooltipProps`
1184
1285
 
1185
1286
  ### Subpath entry points
1186
1287
 
1187
1288
  Each entry point registers only that component and exports only its surface:
1188
1289
 
1189
- | Entry point | Registers | Key exports |
1190
- | ------------------ | ----------------- | ---------------------------------------------------------------------------------------- |
1191
- | `.../button` | `sp-button` | `defineSpectreButton`, `SpectreButtonElement`, button constants and types |
1192
- | `.../input` | `sp-input` | `defineSpectreInput`, `SpectreInputElement`, input constants and types |
1193
- | `.../textarea` | `sp-textarea` | `defineSpectreTextarea`, `SpectreTextareaElement`, `SpectreTextareaProps` |
1194
- | `.../select` | `sp-select` | `defineSpectreSelect`, `SpectreSelectElement`, `SpectreSelectProps` |
1195
- | `.../checkbox` | `sp-checkbox` | `defineSpectreCheckbox`, `SpectreCheckboxElement`, `SpectreCheckboxProps` |
1196
- | `.../radio` | `sp-radio` | `defineSpectreRadio`, `SpectreRadioElement`, `SpectreRadioProps` |
1197
- | `.../label` | `sp-label` | `defineSpectreLabel`, `SpectreLabelElement`, `SpectreLabelProps` |
1198
- | `.../fieldset` | `sp-fieldset` | `defineSpectreFieldset`, `SpectreFieldsetElement`, `SpectreFieldsetProps` |
1199
- | `.../badge` | `sp-badge` | `defineSpectreBadge`, `SpectreBadgeElement`, badge constants and types |
1200
- | `.../card` | `sp-card` | `defineSpectreCard`, `SpectreCardElement`, card constants and types |
1201
- | `.../icon-box` | `sp-icon-box` | `defineSpectreIconBox`, `SpectreIconBoxElement`, icon-box constants and types |
1202
- | `.../rating` | `sp-rating` | `defineSpectreRating`, `SpectreRatingElement`, rating constants and types |
1203
- | `.../testimonial` | `sp-testimonial` | `defineSpectreTestimonial`, `SpectreTestimonialElement`, testimonial constants and types |
1204
- | `.../alert` | `sp-alert` | `defineSpectreAlert`, `SpectreAlertElement`, alert constants and types |
1205
- | `.../avatar` | `sp-avatar` | `defineSpectreAvatar`, `SpectreAvatarElement`, avatar constants and types |
1206
- | `.../spinner` | `sp-spinner` | `defineSpectreSpinner`, `SpectreSpinnerElement`, spinner constants and types |
1207
- | `.../tag` | `sp-tag` | `defineSpectreTag`, `SpectreTagElement`, tag constants and types |
1208
- | `.../pricing-card` | `sp-pricing-card` | `defineSpectrePricingCard`, `SpectrePricingCardElement`, `SpectrePricingCardProps` |
1209
- | `.../container` | `sp-container` | `defineSpectreContainer`, `SpectreContainerElement`, container constants and types |
1210
- | `.../grid` | `sp-grid` | `defineSpectreGrid`, `SpectreGridElement`, grid constants and types |
1211
- | `.../section` | `sp-section` | `defineSpectreSection`, `SpectreSectionElement`, `SpectreSectionProps` |
1212
- | `.../stack` | `sp-stack` | `defineSpectreStack`, `SpectreStackElement`, stack constants and types |
1213
- | `.../nav` | `sp-nav` | `defineSpectreNav`, `SpectreNavElement`, `SpectreNavProps` |
1214
- | `.../nav-item` | `sp-nav-item` | `defineSpectreNavItem`, `SpectreNavItemElement`, `SpectreNavItemProps` |
1215
- | `.../sidebar` | `sp-sidebar` | `defineSpectreSidebar`, `SpectreSidebarElement`, `SpectreSidebarProps` |
1216
- | `.../dropdown` | `sp-dropdown` | `defineSpectreDropdown`, `SpectreDropdownElement`, dropdown constants and types |
1217
- | `.../footer` | `sp-footer` | `defineSpectreFooter`, `SpectreFooterElement`, `SpectreFooterProps` |
1218
- | `.../modal` | `sp-modal` | `defineSpectreModal`, `SpectreModalElement`, `SpectreModalProps` |
1219
- | `.../toast` | `sp-toast` | `defineSpectreToast`, `SpectreToastElement`, toast constants and types |
1220
- | `.../tooltip` | `sp-tooltip` | `defineSpectreTooltip`, `SpectreTooltipElement`, tooltip constants and types |
1290
+ | Entry point | Registers | Key exports |
1291
+ | -------------------- | ------------------- | ---------------------------------------------------------------------------------------- |
1292
+ | `.../button` | `sp-button` | `defineSpectreButton`, `SpectreButtonElement`, button constants and types |
1293
+ | `.../input` | `sp-input` | `defineSpectreInput`, `SpectreInputElement`, input constants and types |
1294
+ | `.../textarea` | `sp-textarea` | `defineSpectreTextarea`, `SpectreTextareaElement`, `SpectreTextareaProps` |
1295
+ | `.../select` | `sp-select` | `defineSpectreSelect`, `SpectreSelectElement`, `SpectreSelectProps` |
1296
+ | `.../checkbox` | `sp-checkbox` | `defineSpectreCheckbox`, `SpectreCheckboxElement`, `SpectreCheckboxProps` |
1297
+ | `.../radio` | `sp-radio` | `defineSpectreRadio`, `SpectreRadioElement`, `SpectreRadioProps` |
1298
+ | `.../label` | `sp-label` | `defineSpectreLabel`, `SpectreLabelElement`, `SpectreLabelProps` |
1299
+ | `.../fieldset` | `sp-fieldset` | `defineSpectreFieldset`, `SpectreFieldsetElement`, `SpectreFieldsetProps` |
1300
+ | `.../badge` | `sp-badge` | `defineSpectreBadge`, `SpectreBadgeElement`, badge constants and types |
1301
+ | `.../card` | `sp-card` | `defineSpectreCard`, `SpectreCardElement`, card constants and types |
1302
+ | `.../icon-box` | `sp-icon-box` | `defineSpectreIconBox`, `SpectreIconBoxElement`, icon-box constants and types |
1303
+ | `.../rating` | `sp-rating` | `defineSpectreRating`, `SpectreRatingElement`, rating constants and types |
1304
+ | `.../testimonial` | `sp-testimonial` | `defineSpectreTestimonial`, `SpectreTestimonialElement`, testimonial constants and types |
1305
+ | `.../alert` | `sp-alert` | `defineSpectreAlert`, `SpectreAlertElement`, alert constants and types |
1306
+ | `.../avatar` | `sp-avatar` | `defineSpectreAvatar`, `SpectreAvatarElement`, avatar constants and types |
1307
+ | `.../spinner` | `sp-spinner` | `defineSpectreSpinner`, `SpectreSpinnerElement`, spinner constants and types |
1308
+ | `.../tag` | `sp-tag` | `defineSpectreTag`, `SpectreTagElement`, tag constants and types |
1309
+ | `.../pricing-card` | `sp-pricing-card` | `defineSpectrePricingCard`, `SpectrePricingCardElement`, `SpectrePricingCardProps` |
1310
+ | `.../container` | `sp-container` | `defineSpectreContainer`, `SpectreContainerElement`, container constants and types |
1311
+ | `.../grid` | `sp-grid` | `defineSpectreGrid`, `SpectreGridElement`, grid constants and types |
1312
+ | `.../section` | `sp-section` | `defineSpectreSection`, `SpectreSectionElement`, `SpectreSectionProps` |
1313
+ | `.../stack` | `sp-stack` | `defineSpectreStack`, `SpectreStackElement`, stack constants and types |
1314
+ | `.../nav` | `sp-nav` | `defineSpectreNav`, `SpectreNavElement`, `SpectreNavProps` |
1315
+ | `.../nav-item` | `sp-nav-item` | `defineSpectreNavItem`, `SpectreNavItemElement`, `SpectreNavItemProps` |
1316
+ | `.../sidebar` | `sp-sidebar` | `defineSpectreSidebar`, `SpectreSidebarElement`, `SpectreSidebarProps` |
1317
+ | `.../sidebar-toggle` | `sp-sidebar-toggle` | `defineSpectreSidebarToggle`, `SpectreSidebarToggleElement`, `SpectreSidebarToggleProps` |
1318
+ | `.../dropdown` | `sp-dropdown` | `defineSpectreDropdown`, `SpectreDropdownElement`, dropdown constants and types |
1319
+ | `.../footer` | `sp-footer` | `defineSpectreFooter`, `SpectreFooterElement`, `SpectreFooterProps` |
1320
+ | `.../modal` | `sp-modal` | `defineSpectreModal`, `SpectreModalElement`, `SpectreModalProps` |
1321
+ | `.../toast` | `sp-toast` | `defineSpectreToast`, `SpectreToastElement`, toast constants and types |
1322
+ | `.../tooltip` | `sp-tooltip` | `defineSpectreTooltip`, `SpectreTooltipElement`, tooltip constants and types |
1221
1323
 
1222
1324
  Size constants are shared between input, textarea, and select. Import
1223
1325
  `spectreInputSizes` / `SpectreInputSize` from `.../input` when needed alongside
@@ -1303,14 +1405,14 @@ pass.
1303
1405
  ## AI And Automation Boundaries
1304
1406
 
1305
1407
  Claude Code (`claude-sonnet-4-6`) is the primary development agent for this
1306
- repository. Codex handles releases, including cutting tagged releases and
1307
- GitHub Releases, and production stabilization. Jules handles small automated
1308
- fixes and dependency updates. GitHub Copilot provides development support.
1309
-
1310
- All AI agents with repository access (Claude Code, Codex, Copilot, Jules)
1311
- have commit, push, and tag authority in this repository. Publishing to npm
1312
- remains Bradley Potts's sole authority. See [AGENTS.md](AGENTS.md) for the
1313
- full commit-policy and release-authority grant.
1408
+ repository. Codex handles releases, including cutting tagged releases and GitHub
1409
+ Releases, and production stabilization. Jules handles small automated fixes and
1410
+ dependency updates. GitHub Copilot provides development support.
1411
+
1412
+ All AI agents with repository access (Claude Code, Codex, Copilot, Jules) have
1413
+ commit, push, and tag authority in this repository. Publishing to npm remains
1414
+ Bradley Potts's sole authority. See [AGENTS.md](AGENTS.md) for the full
1415
+ commit-policy and release-authority grant.
1314
1416
 
1315
1417
  **Protected from automated change:** component public API surface (tags,
1316
1418
  properties, events, slots, ARIA), the light-DOM rendering model, and the