@aurodesignsystem-dev/auro-formkit 0.0.0-pr1611.0 → 0.0.0-pr1613.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 (52) hide show
  1. package/components/checkbox/demo/accessibility.md +15 -4
  2. package/components/checkbox/demo/api.md +4 -3
  3. package/components/checkbox/demo/customize.md +2 -1
  4. package/components/checkbox/demo/customize.min.js +100 -18
  5. package/components/checkbox/demo/getting-started.min.js +100 -18
  6. package/components/checkbox/demo/index.min.js +100 -18
  7. package/components/checkbox/dist/auro-checkbox-group.d.ts +24 -0
  8. package/components/checkbox/dist/index.js +100 -18
  9. package/components/checkbox/dist/registered.js +100 -18
  10. package/components/combobox/demo/customize.min.js +3 -3
  11. package/components/combobox/demo/getting-started.min.js +3 -3
  12. package/components/combobox/demo/index.min.js +3 -3
  13. package/components/combobox/dist/index.js +3 -3
  14. package/components/combobox/dist/registered.js +3 -3
  15. package/components/counter/demo/customize.min.js +2 -2
  16. package/components/counter/demo/getting-started.min.js +2 -2
  17. package/components/counter/demo/index.min.js +2 -2
  18. package/components/counter/dist/index.js +2 -2
  19. package/components/counter/dist/registered.js +2 -2
  20. package/components/datepicker/demo/customize.min.js +3 -3
  21. package/components/datepicker/demo/getting-started.min.js +3 -3
  22. package/components/datepicker/demo/index.min.js +3 -3
  23. package/components/datepicker/dist/index.js +3 -3
  24. package/components/datepicker/dist/registered.js +3 -3
  25. package/components/dropdown/demo/customize.min.js +1 -1
  26. package/components/dropdown/demo/getting-started.min.js +2 -2
  27. package/components/dropdown/demo/index.min.js +1 -1
  28. package/components/dropdown/dist/index.js +1 -1
  29. package/components/dropdown/dist/registered.js +1 -1
  30. package/components/form/demo/customize.min.js +208 -50
  31. package/components/form/demo/getting-started.min.js +208 -50
  32. package/components/form/demo/index.min.js +208 -50
  33. package/components/form/demo/registerDemoDeps.min.js +208 -50
  34. package/components/input/demo/customize.min.js +1 -1
  35. package/components/input/demo/getting-started.min.js +1 -1
  36. package/components/input/demo/index.min.js +1 -1
  37. package/components/input/dist/index.js +1 -1
  38. package/components/input/dist/registered.js +1 -1
  39. package/components/radio/demo/accessibility.md +15 -4
  40. package/components/radio/demo/customize.min.js +93 -17
  41. package/components/radio/demo/getting-started.min.js +93 -17
  42. package/components/radio/demo/index.min.js +93 -17
  43. package/components/radio/dist/auro-radio-group.d.ts +22 -0
  44. package/components/radio/dist/index.js +93 -17
  45. package/components/radio/dist/registered.js +93 -17
  46. package/components/select/demo/customize.min.js +2 -2
  47. package/components/select/demo/getting-started.min.js +2 -2
  48. package/components/select/demo/index.min.js +2 -2
  49. package/components/select/dist/index.js +2 -2
  50. package/components/select/dist/registered.js +2 -2
  51. package/custom-elements.json +1554 -1504
  52. package/package.json +1 -1
@@ -8,12 +8,13 @@ For keyboard interaction details, see the <auro-hyperlink href="keyboard-behavio
8
8
 
9
9
  <auro-header level="2" id="ariaRolesAndAttributes">ARIA Roles and Attributes</auro-header>
10
10
  <auro-header level="3" id="radioGroup">Radio Group</auro-header>
11
- The `<auro-radio-group>` element uses a `<fieldset>` with a `<legend>` internally, providing native grouping semantics:
11
+ The `<auro-radio-group>` element uses a `<fieldset>` with a `<legend>` internally, providing native grouping semantics. These attributes are applied to that shadow-DOM `<fieldset>`, **not** to the `<auro-radio-group>` host element:
12
12
 
13
13
  | Attribute | Value | Description |
14
14
  |---|---|---|
15
- | `role` | `radiogroup` (implicit via `fieldset`) | Groups related radio buttons together. |
16
- | `aria-invalid` | `true` / `false` | Reflects whether the group is currently in an invalid state. |
15
+ | `role` | `radiogroup` | Groups related radio buttons together. Set explicitly on the `<fieldset>`; a bare `<fieldset>` would otherwise expose the implicit role `group`. |
16
+ | `aria-invalid` | `true` | Present only while the group is in an invalid state. The attribute is **omitted entirely** when the group is valid — it is never set to `false`. |
17
+ | `aria-describedby` | id reference | Points at the `id` of the group's help-text/error element, so assistive technology can associate the message with the group on demand rather than relying only on the one-time live-region announcement. |
17
18
 
18
19
  <auro-header level="3" id="radioElement">Radio</auro-header>
19
20
  Each `<auro-radio>` renders a native `<input type="radio">` inside its shadow DOM:
@@ -23,12 +24,22 @@ Each `<auro-radio>` renders a native `<input type="radio">` inside its shadow DO
23
24
  | `type` | `radio` | Native radio input type. |
24
25
  | `aria-checked` | `true` / `false` | Reflects the selected state of the radio button. |
25
26
  | `aria-disabled` | `true` / `false` | Indicates whether the radio button is disabled. |
27
+ | `aria-invalid` | `true` | Mirrored onto each radio from the group while the group is invalid, and removed when it becomes valid. Omitted rather than set to `false`. |
28
+
29
+ <auro-header level="4" id="invalidStatePlacement">Why the invalid state appears twice</auro-header>
30
+ While the group is invalid, `aria-invalid` is set on both the `<fieldset>` and every individual `<auro-radio>`. This is intentional. Some assistive-technology and browser combinations announce a container's invalid state only when focus first enters the group, not on each subsequent arrow-key move between radios; mirroring the state onto each radio keeps it conveyed throughout. As a side effect, VoiceOver may say "invalid data" twice in a single utterance when you Tab into an invalid group.
31
+
32
+ The group-level placement is unambiguous: `aria-invalid` is a global attribute in ARIA 1.1, and although ARIA 1.2 deprecates that global use in favor of a supported-role list, `radiogroup` is on that list — so the `<fieldset>` is spec-clean under either version. The **per-radio** placement rests on the looser footing: `radio` is *not* on the ARIA 1.2 supported-role list, so it depends on the same deprecated-global allowance that the [Checkbox accessibility page](../../checkbox/demo/accessibility.html) documents for its `group` fieldset. It is not a *prohibited* attribute for `radio`, current axe-core resolves it as global and reports no violation, and the per-radio redundancy is what keeps the invalid state conveyed while arrowing through options — so it is kept deliberately. An automated axe assertion in the component's test suite pins this outcome, so a change in tooling surfaces there rather than in a consumer's audit.
33
+
34
+ <auro-header level="4" id="attributePlacementNote">Attribute placement</auro-header>
35
+ `aria-invalid` is applied to the internal `<fieldset>`, which is the element that carries `role="radiogroup"` — ARIA state has to live on the same element as the role it describes. It is **not** set on the `<auro-radio-group>` host element. Do not write CSS selectors or test assertions against `auro-radio-group[aria-invalid]`; query the `part="radio-group"` fieldset or read the `validity` property instead.
26
36
 
27
37
  <auro-header level="2" id="screenReaderAnnouncements">Screen Reader Announcements</auro-header>
28
38
  - **Focus** — When focus moves to a radio button, the screen reader announces the radio label, its selected/unselected state, its position in the group (e.g. "1 of 3"), and role ("radio button").
29
39
  - **State change** — Selecting a radio button announces the new state ("selected").
30
40
  - **Group context** — The legend text provides group context when navigating between groups.
31
- - **Error** — When validation fails, the error message is announced to screen reader users.
41
+ - **Error** — When validation fails, the error message is announced immediately via the help text's `role="alert"` live region, and stays discoverable afterward through the group's `aria-describedby` association.
42
+ - **Invalid state** — While the group is invalid, entering it or moving between its radios conveys the invalid state.
32
43
 
33
44
  <auro-header level="2" id="accessibleLabels">Accessible Labels</auro-header>
34
45
  - The `legend` slot content provides the accessible group label via the native `<legend>` element.
@@ -1001,6 +1001,48 @@ class AuroDependencyVersioning {
1001
1001
  }
1002
1002
  }
1003
1003
 
1004
+ /**
1005
+ * Generates a v4 UUID with a three-tier fallback for insecure contexts.
1006
+ *
1007
+ * Tier 1 (secure contexts): crypto.randomUUID() — native, fully random.
1008
+ * Tier 2 (insecure contexts): crypto.getRandomValues() — available on all
1009
+ * modern browsers regardless of secure-context status.
1010
+ * Tier 3 (last resort, no crypto API): new Date().getTime() — lower entropy,
1011
+ * but sufficient for element IDs where collision risk is negligible.
1012
+ *
1013
+ * See: https://w3c.github.io/webcrypto/#dom-crypto-randomuuid (secure-context restriction)
1014
+ */
1015
+ function generateUUID() {
1016
+ let uuid;
1017
+
1018
+ if (
1019
+ typeof crypto !== "undefined" &&
1020
+ typeof crypto.randomUUID === "function"
1021
+ ) {
1022
+ uuid = crypto.randomUUID();
1023
+ } else if (
1024
+ typeof crypto !== "undefined" &&
1025
+ typeof crypto.getRandomValues === "function"
1026
+ ) {
1027
+ const bytes = new Uint8Array(16);
1028
+ crypto.getRandomValues(bytes);
1029
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
1030
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
1031
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0"));
1032
+ uuid = `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
1033
+ } else {
1034
+ let d = new Date().getTime();
1035
+ uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1036
+ const r = (d % 16) | 0;
1037
+ d = (d - r) / 16 || new Date().getTime();
1038
+ return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
1039
+ });
1040
+ }
1041
+
1042
+ // CSS selectors require IDs starting with a letter; replace a leading digit with 'a'.
1043
+ return /^[0-9]/.test(uuid) ? `a${uuid.slice(1)}` : uuid;
1044
+ }
1045
+
1004
1046
  var colorCss = i$5`:host([error]){--ds-auro-helptext-color: var(--ds-basic-color-status-error, #e31f26)}:host([onDark]),:host([appearance=inverse]){--ds-auro-helptext-color: var(--ds-basic-color-texticon-inverse-muted, #ccd2db)}:host([onDark][error]),:host([appearance=inverse][error]){--ds-auro-helptext-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}.helptext-wrapper{color:var(--ds-auro-helptext-color)}`;
1005
1047
 
1006
1048
  var styleCss = i$5`.body-default{font-size:var(--wcss-body-default-font-size, 1rem);font-weight:var(--wcss-body-default-weight, );line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-default-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-default-emphasized{font-size:var(--wcss-body-default-emphasized-font-size, 1rem);font-weight:var(--wcss-body-default-emphasized-weight, );line-height:var(--wcss-body-default-emphasized-line-height, 1.5rem)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);font-weight:var(--wcss-body-lg-weight, );line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-lg,.body-lg-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg-emphasized{font-size:var(--wcss-body-lg-emphasized-font-size, 1.125rem);font-weight:var(--wcss-body-lg-emphasized-weight, );line-height:var(--wcss-body-lg-emphasized-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, 0.875rem);font-weight:var(--wcss-body-sm-weight, );line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-sm-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-sm-emphasized{font-size:var(--wcss-body-sm-emphasized-font-size, 0.875rem);font-weight:var(--wcss-body-sm-emphasized-weight, );line-height:var(--wcss-body-sm-emphasized-line-height, 1.25rem)}.body-xs{font-size:var(--wcss-body-xs-font-size, 0.75rem);font-weight:var(--wcss-body-xs-weight, );line-height:var(--wcss-body-xs-line-height, 1rem)}.body-xs,.body-xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs-emphasized{font-size:var(--wcss-body-xs-emphasized-font-size, 0.75rem);font-weight:var(--wcss-body-xs-emphasized-weight, );line-height:var(--wcss-body-xs-emphasized-line-height, 1rem)}.body-2xs{font-size:var(--wcss-body-2xs-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-weight, );line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.body-2xs,.body-2xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-2xs-emphasized{font-size:var(--wcss-body-2xs-emphasized-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-emphasized-weight, );line-height:var(--wcss-body-2xs-emphasized-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 300);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 300);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}:host{position:relative;display:block}.helptext-wrapper{display:none}.helptext-wrapper[visible]{display:block}::slotted(*:not(:empty)){margin-top:var(--ds-size-50, 0.25rem);margin-bottom:0}::slotted(p){margin-block:0}`;
@@ -1235,7 +1277,7 @@ class AuroHelpText extends i$2 {
1235
1277
  }
1236
1278
  }
1237
1279
 
1238
- var formkitVersion = '202609050113';
1280
+ var formkitVersion = '202609082147';
1239
1281
 
1240
1282
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1241
1283
  // See LICENSE in the project root for license information.
@@ -1306,6 +1348,11 @@ class AuroRadioGroup extends i$2 {
1306
1348
  * @private
1307
1349
  */
1308
1350
  this.helpTextTag = versioning.generateTag('auro-formkit-radio-helptext', formkitVersion, AuroHelpText);
1351
+
1352
+ /**
1353
+ * @private
1354
+ */
1355
+ this.uniqueId = generateUUID();
1309
1356
  }
1310
1357
 
1311
1358
  static get styles() {
@@ -1558,20 +1605,42 @@ class AuroRadioGroup extends i$2 {
1558
1605
  }
1559
1606
 
1560
1607
  if (changedProperties.has('validity')) {
1561
- if (this.validity && this.validity !== 'valid') {
1562
- this.setAttribute('aria-invalid', 'true');
1608
+ this.syncItemValidity();
1609
+ }
1610
+ }
1563
1611
 
1564
- this.items.forEach((el) => {
1565
- el.setAttribute('error', true);
1566
- });
1567
- } else {
1568
- this.removeAttribute('aria-invalid');
1612
+ /**
1613
+ * Whether the group is currently in an invalid state.
1614
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1615
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1616
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1617
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1618
+ * @private
1619
+ * @returns {boolean}
1620
+ */
1621
+ get isInvalid() {
1622
+ return Boolean(this.validity && this.validity !== 'valid');
1623
+ }
1569
1624
 
1570
- this.items.forEach((el) => {
1571
- el.removeAttribute('error');
1572
- });
1625
+ /**
1626
+ * Method for mirroring the group's invalid state onto each radio input.
1627
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1628
+ * reconnect can happen without `validity` itself changing.
1629
+ * @private
1630
+ * @returns {void}
1631
+ */
1632
+ syncItemValidity() {
1633
+ const invalid = this.isInvalid;
1634
+
1635
+ this.items.forEach((el) => {
1636
+ if (invalid) {
1637
+ el.setAttribute('error', true);
1638
+ el.setAttribute('aria-invalid', 'true');
1639
+ } else {
1640
+ el.removeAttribute('error');
1641
+ el.removeAttribute('aria-invalid');
1573
1642
  }
1574
- }
1643
+ });
1575
1644
  }
1576
1645
 
1577
1646
  /**
@@ -1627,8 +1696,9 @@ class AuroRadioGroup extends i$2 {
1627
1696
 
1628
1697
  this.items.forEach((el) => {
1629
1698
  el.required = this.required;
1630
- el.error = Boolean(this.error);
1631
1699
  });
1700
+
1701
+ this.syncItemValidity();
1632
1702
  }
1633
1703
 
1634
1704
  /**
@@ -1773,7 +1843,13 @@ class AuroRadioGroup extends i$2 {
1773
1843
  };
1774
1844
 
1775
1845
  return u`
1776
- <fieldset class="${e(groupClasses)}" part="radio-group" role="radiogroup">
1846
+ <fieldset
1847
+ class="${e(groupClasses)}"
1848
+ part="radio-group"
1849
+ role="radiogroup"
1850
+ aria-invalid="${o$1(this.isInvalid ? 'true' : undefined)}"
1851
+ aria-describedby="${this.uniqueId}"
1852
+ >
1777
1853
  <legend class="${e(legendClasses)}">
1778
1854
  <slot name="legend" @slotchange=${this.handleLegendSlotChange}></slot>
1779
1855
  ${this.required ? undefined : u`<slot name="optionalLabel"> (optional)</slot>`}
@@ -1781,13 +1857,13 @@ class AuroRadioGroup extends i$2 {
1781
1857
  <slot @slotchange=${this.handleSlotChange}></slot>
1782
1858
  </fieldset>
1783
1859
 
1784
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1860
+ ${!this.isInvalid
1785
1861
  ? u`
1786
- <${this.helpTextTag} appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1862
+ <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1787
1863
  <slot name="helpText"></slot>
1788
1864
  </${this.helpTextTag}>`
1789
1865
  : u`
1790
- <${this.helpTextTag} appearance="${this.onDark ? 'inverse' : this.appearance}" role="alert" error aria-live="assertive" part="helpText">
1866
+ <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" role="alert" error aria-live="assertive" part="helpText">
1791
1867
  ${this.errorMessage}
1792
1868
  </${this.helpTextTag}>`
1793
1869
  }
@@ -1001,6 +1001,48 @@ class AuroDependencyVersioning {
1001
1001
  }
1002
1002
  }
1003
1003
 
1004
+ /**
1005
+ * Generates a v4 UUID with a three-tier fallback for insecure contexts.
1006
+ *
1007
+ * Tier 1 (secure contexts): crypto.randomUUID() — native, fully random.
1008
+ * Tier 2 (insecure contexts): crypto.getRandomValues() — available on all
1009
+ * modern browsers regardless of secure-context status.
1010
+ * Tier 3 (last resort, no crypto API): new Date().getTime() — lower entropy,
1011
+ * but sufficient for element IDs where collision risk is negligible.
1012
+ *
1013
+ * See: https://w3c.github.io/webcrypto/#dom-crypto-randomuuid (secure-context restriction)
1014
+ */
1015
+ function generateUUID() {
1016
+ let uuid;
1017
+
1018
+ if (
1019
+ typeof crypto !== "undefined" &&
1020
+ typeof crypto.randomUUID === "function"
1021
+ ) {
1022
+ uuid = crypto.randomUUID();
1023
+ } else if (
1024
+ typeof crypto !== "undefined" &&
1025
+ typeof crypto.getRandomValues === "function"
1026
+ ) {
1027
+ const bytes = new Uint8Array(16);
1028
+ crypto.getRandomValues(bytes);
1029
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
1030
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
1031
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0"));
1032
+ uuid = `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
1033
+ } else {
1034
+ let d = new Date().getTime();
1035
+ uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1036
+ const r = (d % 16) | 0;
1037
+ d = (d - r) / 16 || new Date().getTime();
1038
+ return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
1039
+ });
1040
+ }
1041
+
1042
+ // CSS selectors require IDs starting with a letter; replace a leading digit with 'a'.
1043
+ return /^[0-9]/.test(uuid) ? `a${uuid.slice(1)}` : uuid;
1044
+ }
1045
+
1004
1046
  var colorCss = i$5`:host([error]){--ds-auro-helptext-color: var(--ds-basic-color-status-error, #e31f26)}:host([onDark]),:host([appearance=inverse]){--ds-auro-helptext-color: var(--ds-basic-color-texticon-inverse-muted, #ccd2db)}:host([onDark][error]),:host([appearance=inverse][error]){--ds-auro-helptext-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}.helptext-wrapper{color:var(--ds-auro-helptext-color)}`;
1005
1047
 
1006
1048
  var styleCss = i$5`.body-default{font-size:var(--wcss-body-default-font-size, 1rem);font-weight:var(--wcss-body-default-weight, );line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-default-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-default-emphasized{font-size:var(--wcss-body-default-emphasized-font-size, 1rem);font-weight:var(--wcss-body-default-emphasized-weight, );line-height:var(--wcss-body-default-emphasized-line-height, 1.5rem)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);font-weight:var(--wcss-body-lg-weight, );line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-lg,.body-lg-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg-emphasized{font-size:var(--wcss-body-lg-emphasized-font-size, 1.125rem);font-weight:var(--wcss-body-lg-emphasized-weight, );line-height:var(--wcss-body-lg-emphasized-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, 0.875rem);font-weight:var(--wcss-body-sm-weight, );line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-sm-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-sm-emphasized{font-size:var(--wcss-body-sm-emphasized-font-size, 0.875rem);font-weight:var(--wcss-body-sm-emphasized-weight, );line-height:var(--wcss-body-sm-emphasized-line-height, 1.25rem)}.body-xs{font-size:var(--wcss-body-xs-font-size, 0.75rem);font-weight:var(--wcss-body-xs-weight, );line-height:var(--wcss-body-xs-line-height, 1rem)}.body-xs,.body-xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs-emphasized{font-size:var(--wcss-body-xs-emphasized-font-size, 0.75rem);font-weight:var(--wcss-body-xs-emphasized-weight, );line-height:var(--wcss-body-xs-emphasized-line-height, 1rem)}.body-2xs{font-size:var(--wcss-body-2xs-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-weight, );line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.body-2xs,.body-2xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-2xs-emphasized{font-size:var(--wcss-body-2xs-emphasized-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-emphasized-weight, );line-height:var(--wcss-body-2xs-emphasized-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 300);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 300);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}:host{position:relative;display:block}.helptext-wrapper{display:none}.helptext-wrapper[visible]{display:block}::slotted(*:not(:empty)){margin-top:var(--ds-size-50, 0.25rem);margin-bottom:0}::slotted(p){margin-block:0}`;
@@ -1235,7 +1277,7 @@ class AuroHelpText extends i$2 {
1235
1277
  }
1236
1278
  }
1237
1279
 
1238
- var formkitVersion = '202609050113';
1280
+ var formkitVersion = '202609082147';
1239
1281
 
1240
1282
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1241
1283
  // See LICENSE in the project root for license information.
@@ -1306,6 +1348,11 @@ class AuroRadioGroup extends i$2 {
1306
1348
  * @private
1307
1349
  */
1308
1350
  this.helpTextTag = versioning.generateTag('auro-formkit-radio-helptext', formkitVersion, AuroHelpText);
1351
+
1352
+ /**
1353
+ * @private
1354
+ */
1355
+ this.uniqueId = generateUUID();
1309
1356
  }
1310
1357
 
1311
1358
  static get styles() {
@@ -1558,20 +1605,42 @@ class AuroRadioGroup extends i$2 {
1558
1605
  }
1559
1606
 
1560
1607
  if (changedProperties.has('validity')) {
1561
- if (this.validity && this.validity !== 'valid') {
1562
- this.setAttribute('aria-invalid', 'true');
1608
+ this.syncItemValidity();
1609
+ }
1610
+ }
1563
1611
 
1564
- this.items.forEach((el) => {
1565
- el.setAttribute('error', true);
1566
- });
1567
- } else {
1568
- this.removeAttribute('aria-invalid');
1612
+ /**
1613
+ * Whether the group is currently in an invalid state.
1614
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1615
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1616
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1617
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1618
+ * @private
1619
+ * @returns {boolean}
1620
+ */
1621
+ get isInvalid() {
1622
+ return Boolean(this.validity && this.validity !== 'valid');
1623
+ }
1569
1624
 
1570
- this.items.forEach((el) => {
1571
- el.removeAttribute('error');
1572
- });
1625
+ /**
1626
+ * Method for mirroring the group's invalid state onto each radio input.
1627
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1628
+ * reconnect can happen without `validity` itself changing.
1629
+ * @private
1630
+ * @returns {void}
1631
+ */
1632
+ syncItemValidity() {
1633
+ const invalid = this.isInvalid;
1634
+
1635
+ this.items.forEach((el) => {
1636
+ if (invalid) {
1637
+ el.setAttribute('error', true);
1638
+ el.setAttribute('aria-invalid', 'true');
1639
+ } else {
1640
+ el.removeAttribute('error');
1641
+ el.removeAttribute('aria-invalid');
1573
1642
  }
1574
- }
1643
+ });
1575
1644
  }
1576
1645
 
1577
1646
  /**
@@ -1627,8 +1696,9 @@ class AuroRadioGroup extends i$2 {
1627
1696
 
1628
1697
  this.items.forEach((el) => {
1629
1698
  el.required = this.required;
1630
- el.error = Boolean(this.error);
1631
1699
  });
1700
+
1701
+ this.syncItemValidity();
1632
1702
  }
1633
1703
 
1634
1704
  /**
@@ -1773,7 +1843,13 @@ class AuroRadioGroup extends i$2 {
1773
1843
  };
1774
1844
 
1775
1845
  return u`
1776
- <fieldset class="${e(groupClasses)}" part="radio-group" role="radiogroup">
1846
+ <fieldset
1847
+ class="${e(groupClasses)}"
1848
+ part="radio-group"
1849
+ role="radiogroup"
1850
+ aria-invalid="${o$1(this.isInvalid ? 'true' : undefined)}"
1851
+ aria-describedby="${this.uniqueId}"
1852
+ >
1777
1853
  <legend class="${e(legendClasses)}">
1778
1854
  <slot name="legend" @slotchange=${this.handleLegendSlotChange}></slot>
1779
1855
  ${this.required ? undefined : u`<slot name="optionalLabel"> (optional)</slot>`}
@@ -1781,13 +1857,13 @@ class AuroRadioGroup extends i$2 {
1781
1857
  <slot @slotchange=${this.handleSlotChange}></slot>
1782
1858
  </fieldset>
1783
1859
 
1784
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1860
+ ${!this.isInvalid
1785
1861
  ? u`
1786
- <${this.helpTextTag} appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1862
+ <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1787
1863
  <slot name="helpText"></slot>
1788
1864
  </${this.helpTextTag}>`
1789
1865
  : u`
1790
- <${this.helpTextTag} appearance="${this.onDark ? 'inverse' : this.appearance}" role="alert" error aria-live="assertive" part="helpText">
1866
+ <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" role="alert" error aria-live="assertive" part="helpText">
1791
1867
  ${this.errorMessage}
1792
1868
  </${this.helpTextTag}>`
1793
1869
  }
@@ -1001,6 +1001,48 @@ class AuroDependencyVersioning {
1001
1001
  }
1002
1002
  }
1003
1003
 
1004
+ /**
1005
+ * Generates a v4 UUID with a three-tier fallback for insecure contexts.
1006
+ *
1007
+ * Tier 1 (secure contexts): crypto.randomUUID() — native, fully random.
1008
+ * Tier 2 (insecure contexts): crypto.getRandomValues() — available on all
1009
+ * modern browsers regardless of secure-context status.
1010
+ * Tier 3 (last resort, no crypto API): new Date().getTime() — lower entropy,
1011
+ * but sufficient for element IDs where collision risk is negligible.
1012
+ *
1013
+ * See: https://w3c.github.io/webcrypto/#dom-crypto-randomuuid (secure-context restriction)
1014
+ */
1015
+ function generateUUID() {
1016
+ let uuid;
1017
+
1018
+ if (
1019
+ typeof crypto !== "undefined" &&
1020
+ typeof crypto.randomUUID === "function"
1021
+ ) {
1022
+ uuid = crypto.randomUUID();
1023
+ } else if (
1024
+ typeof crypto !== "undefined" &&
1025
+ typeof crypto.getRandomValues === "function"
1026
+ ) {
1027
+ const bytes = new Uint8Array(16);
1028
+ crypto.getRandomValues(bytes);
1029
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
1030
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
1031
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0"));
1032
+ uuid = `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
1033
+ } else {
1034
+ let d = new Date().getTime();
1035
+ uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1036
+ const r = (d % 16) | 0;
1037
+ d = (d - r) / 16 || new Date().getTime();
1038
+ return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
1039
+ });
1040
+ }
1041
+
1042
+ // CSS selectors require IDs starting with a letter; replace a leading digit with 'a'.
1043
+ return /^[0-9]/.test(uuid) ? `a${uuid.slice(1)}` : uuid;
1044
+ }
1045
+
1004
1046
  var colorCss = i$5`:host([error]){--ds-auro-helptext-color: var(--ds-basic-color-status-error, #e31f26)}:host([onDark]),:host([appearance=inverse]){--ds-auro-helptext-color: var(--ds-basic-color-texticon-inverse-muted, #ccd2db)}:host([onDark][error]),:host([appearance=inverse][error]){--ds-auro-helptext-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}.helptext-wrapper{color:var(--ds-auro-helptext-color)}`;
1005
1047
 
1006
1048
  var styleCss = i$5`.body-default{font-size:var(--wcss-body-default-font-size, 1rem);font-weight:var(--wcss-body-default-weight, );line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-default-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-default-emphasized{font-size:var(--wcss-body-default-emphasized-font-size, 1rem);font-weight:var(--wcss-body-default-emphasized-weight, );line-height:var(--wcss-body-default-emphasized-line-height, 1.5rem)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);font-weight:var(--wcss-body-lg-weight, );line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-lg,.body-lg-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg-emphasized{font-size:var(--wcss-body-lg-emphasized-font-size, 1.125rem);font-weight:var(--wcss-body-lg-emphasized-weight, );line-height:var(--wcss-body-lg-emphasized-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, 0.875rem);font-weight:var(--wcss-body-sm-weight, );line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-sm-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-sm-emphasized{font-size:var(--wcss-body-sm-emphasized-font-size, 0.875rem);font-weight:var(--wcss-body-sm-emphasized-weight, );line-height:var(--wcss-body-sm-emphasized-line-height, 1.25rem)}.body-xs{font-size:var(--wcss-body-xs-font-size, 0.75rem);font-weight:var(--wcss-body-xs-weight, );line-height:var(--wcss-body-xs-line-height, 1rem)}.body-xs,.body-xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs-emphasized{font-size:var(--wcss-body-xs-emphasized-font-size, 0.75rem);font-weight:var(--wcss-body-xs-emphasized-weight, );line-height:var(--wcss-body-xs-emphasized-line-height, 1rem)}.body-2xs{font-size:var(--wcss-body-2xs-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-weight, );line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.body-2xs,.body-2xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-2xs-emphasized{font-size:var(--wcss-body-2xs-emphasized-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-emphasized-weight, );line-height:var(--wcss-body-2xs-emphasized-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 300);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 300);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}:host{position:relative;display:block}.helptext-wrapper{display:none}.helptext-wrapper[visible]{display:block}::slotted(*:not(:empty)){margin-top:var(--ds-size-50, 0.25rem);margin-bottom:0}::slotted(p){margin-block:0}`;
@@ -1235,7 +1277,7 @@ class AuroHelpText extends i$2 {
1235
1277
  }
1236
1278
  }
1237
1279
 
1238
- var formkitVersion = '202609050113';
1280
+ var formkitVersion = '202609082147';
1239
1281
 
1240
1282
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1241
1283
  // See LICENSE in the project root for license information.
@@ -1306,6 +1348,11 @@ class AuroRadioGroup extends i$2 {
1306
1348
  * @private
1307
1349
  */
1308
1350
  this.helpTextTag = versioning.generateTag('auro-formkit-radio-helptext', formkitVersion, AuroHelpText);
1351
+
1352
+ /**
1353
+ * @private
1354
+ */
1355
+ this.uniqueId = generateUUID();
1309
1356
  }
1310
1357
 
1311
1358
  static get styles() {
@@ -1558,20 +1605,42 @@ class AuroRadioGroup extends i$2 {
1558
1605
  }
1559
1606
 
1560
1607
  if (changedProperties.has('validity')) {
1561
- if (this.validity && this.validity !== 'valid') {
1562
- this.setAttribute('aria-invalid', 'true');
1608
+ this.syncItemValidity();
1609
+ }
1610
+ }
1563
1611
 
1564
- this.items.forEach((el) => {
1565
- el.setAttribute('error', true);
1566
- });
1567
- } else {
1568
- this.removeAttribute('aria-invalid');
1612
+ /**
1613
+ * Whether the group is currently in an invalid state.
1614
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1615
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1616
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1617
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1618
+ * @private
1619
+ * @returns {boolean}
1620
+ */
1621
+ get isInvalid() {
1622
+ return Boolean(this.validity && this.validity !== 'valid');
1623
+ }
1569
1624
 
1570
- this.items.forEach((el) => {
1571
- el.removeAttribute('error');
1572
- });
1625
+ /**
1626
+ * Method for mirroring the group's invalid state onto each radio input.
1627
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1628
+ * reconnect can happen without `validity` itself changing.
1629
+ * @private
1630
+ * @returns {void}
1631
+ */
1632
+ syncItemValidity() {
1633
+ const invalid = this.isInvalid;
1634
+
1635
+ this.items.forEach((el) => {
1636
+ if (invalid) {
1637
+ el.setAttribute('error', true);
1638
+ el.setAttribute('aria-invalid', 'true');
1639
+ } else {
1640
+ el.removeAttribute('error');
1641
+ el.removeAttribute('aria-invalid');
1573
1642
  }
1574
- }
1643
+ });
1575
1644
  }
1576
1645
 
1577
1646
  /**
@@ -1627,8 +1696,9 @@ class AuroRadioGroup extends i$2 {
1627
1696
 
1628
1697
  this.items.forEach((el) => {
1629
1698
  el.required = this.required;
1630
- el.error = Boolean(this.error);
1631
1699
  });
1700
+
1701
+ this.syncItemValidity();
1632
1702
  }
1633
1703
 
1634
1704
  /**
@@ -1773,7 +1843,13 @@ class AuroRadioGroup extends i$2 {
1773
1843
  };
1774
1844
 
1775
1845
  return u`
1776
- <fieldset class="${e(groupClasses)}" part="radio-group" role="radiogroup">
1846
+ <fieldset
1847
+ class="${e(groupClasses)}"
1848
+ part="radio-group"
1849
+ role="radiogroup"
1850
+ aria-invalid="${o$1(this.isInvalid ? 'true' : undefined)}"
1851
+ aria-describedby="${this.uniqueId}"
1852
+ >
1777
1853
  <legend class="${e(legendClasses)}">
1778
1854
  <slot name="legend" @slotchange=${this.handleLegendSlotChange}></slot>
1779
1855
  ${this.required ? undefined : u`<slot name="optionalLabel"> (optional)</slot>`}
@@ -1781,13 +1857,13 @@ class AuroRadioGroup extends i$2 {
1781
1857
  <slot @slotchange=${this.handleSlotChange}></slot>
1782
1858
  </fieldset>
1783
1859
 
1784
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1860
+ ${!this.isInvalid
1785
1861
  ? u`
1786
- <${this.helpTextTag} appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1862
+ <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1787
1863
  <slot name="helpText"></slot>
1788
1864
  </${this.helpTextTag}>`
1789
1865
  : u`
1790
- <${this.helpTextTag} appearance="${this.onDark ? 'inverse' : this.appearance}" role="alert" error aria-live="assertive" part="helpText">
1866
+ <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" role="alert" error aria-live="assertive" part="helpText">
1791
1867
  ${this.errorMessage}
1792
1868
  </${this.helpTextTag}>`
1793
1869
  }
@@ -161,6 +161,10 @@ export class AuroRadioGroup extends LitElement {
161
161
  * @private
162
162
  */
163
163
  private helpTextTag;
164
+ /**
165
+ * @private
166
+ */
167
+ private uniqueId;
164
168
  firstUpdated(): void;
165
169
  /**
166
170
  * Method for handling of selection of a radio element.
@@ -182,6 +186,24 @@ export class AuroRadioGroup extends LitElement {
182
186
  * @returns {void}
183
187
  */
184
188
  updated(changedProperties: Map<string, any>): void;
189
+ /**
190
+ * Whether the group is currently in an invalid state.
191
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
192
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
193
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
194
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
195
+ * @private
196
+ * @returns {boolean}
197
+ */
198
+ private get isInvalid();
199
+ /**
200
+ * Method for mirroring the group's invalid state onto each radio input.
201
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
202
+ * reconnect can happen without `validity` itself changing.
203
+ * @private
204
+ * @returns {void}
205
+ */
206
+ private syncItemValidity;
185
207
  /**
186
208
  * Resets component to initial state.
187
209
  * @returns {void}