@aurodesignsystem-dev/auro-formkit 0.0.0-pr1608.0 → 0.0.0-pr1608.2

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 (51) hide show
  1. package/components/checkbox/demo/accessibility.md +15 -4
  2. package/components/checkbox/demo/customize.min.js +40 -12
  3. package/components/checkbox/demo/getting-started.min.js +40 -12
  4. package/components/checkbox/demo/index.min.js +40 -12
  5. package/components/checkbox/dist/auro-checkbox-group.d.ts +19 -0
  6. package/components/checkbox/dist/index.js +40 -12
  7. package/components/checkbox/dist/registered.js +40 -12
  8. package/components/combobox/demo/customize.min.js +46 -4
  9. package/components/combobox/demo/getting-started.min.js +46 -4
  10. package/components/combobox/demo/index.min.js +46 -4
  11. package/components/combobox/dist/index.js +46 -4
  12. package/components/combobox/dist/registered.js +46 -4
  13. package/components/counter/demo/customize.min.js +339 -23
  14. package/components/counter/demo/getting-started.min.js +339 -23
  15. package/components/counter/demo/index.min.js +339 -23
  16. package/components/counter/dist/counterGroupKeyboardStrategy.d.ts +1 -0
  17. package/components/counter/dist/index.js +339 -23
  18. package/components/counter/dist/registered.js +339 -23
  19. package/components/datepicker/demo/customize.min.js +46 -4
  20. package/components/datepicker/demo/getting-started.min.js +46 -4
  21. package/components/datepicker/demo/index.min.js +46 -4
  22. package/components/datepicker/dist/index.js +46 -4
  23. package/components/datepicker/dist/registered.js +46 -4
  24. package/components/dropdown/demo/customize.min.js +44 -2
  25. package/components/dropdown/demo/getting-started.min.js +45 -3
  26. package/components/dropdown/demo/index.min.js +44 -2
  27. package/components/dropdown/dist/index.js +44 -2
  28. package/components/dropdown/dist/registered.js +44 -2
  29. package/components/form/demo/customize.min.js +556 -61
  30. package/components/form/demo/getting-started.min.js +556 -61
  31. package/components/form/demo/index.min.js +556 -61
  32. package/components/form/demo/registerDemoDeps.min.js +556 -61
  33. package/components/input/demo/customize.min.js +1 -1
  34. package/components/input/demo/getting-started.min.js +1 -1
  35. package/components/input/demo/index.min.js +1 -1
  36. package/components/input/dist/index.js +1 -1
  37. package/components/input/dist/registered.js +1 -1
  38. package/components/radio/demo/accessibility.md +15 -4
  39. package/components/radio/demo/customize.min.js +39 -14
  40. package/components/radio/demo/getting-started.min.js +39 -14
  41. package/components/radio/demo/index.min.js +39 -14
  42. package/components/radio/dist/auro-radio-group.d.ts +18 -0
  43. package/components/radio/dist/index.js +39 -14
  44. package/components/radio/dist/registered.js +39 -14
  45. package/components/select/demo/customize.min.js +45 -3
  46. package/components/select/demo/getting-started.min.js +45 -3
  47. package/components/select/demo/index.min.js +45 -3
  48. package/components/select/dist/index.js +45 -3
  49. package/components/select/dist/registered.js +45 -3
  50. package/custom-elements.json +1814 -1768
  51. package/package.json +3 -3
@@ -12396,7 +12396,7 @@ class AuroHelpText extends i$3 {
12396
12396
  }
12397
12397
  }
12398
12398
 
12399
- var formkitVersion = '202609021913';
12399
+ var formkitVersion = '202609030018';
12400
12400
 
12401
12401
  /**
12402
12402
  * @license
@@ -12396,7 +12396,7 @@ class AuroHelpText extends i$3 {
12396
12396
  }
12397
12397
  }
12398
12398
 
12399
- var formkitVersion = '202609021913';
12399
+ var formkitVersion = '202609030018';
12400
12400
 
12401
12401
  /**
12402
12402
  * @license
@@ -12396,7 +12396,7 @@ class AuroHelpText extends i$3 {
12396
12396
  }
12397
12397
  }
12398
12398
 
12399
- var formkitVersion = '202609021913';
12399
+ var formkitVersion = '202609030018';
12400
12400
 
12401
12401
  /**
12402
12402
  * @license
@@ -12338,7 +12338,7 @@ class AuroHelpText extends LitElement {
12338
12338
  }
12339
12339
  }
12340
12340
 
12341
- var formkitVersion = '202609021913';
12341
+ var formkitVersion = '202609030018';
12342
12342
 
12343
12343
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12344
12344
  // See LICENSE in the project root for license information.
@@ -12338,7 +12338,7 @@ class AuroHelpText extends LitElement {
12338
12338
  }
12339
12339
  }
12340
12340
 
12341
- var formkitVersion = '202609021913';
12341
+ var formkitVersion = '202609030018';
12342
12342
 
12343
12343
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12344
12344
  // See LICENSE in the project root for license information.
@@ -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.
@@ -1251,7 +1251,7 @@ class AuroHelpText extends i$2 {
1251
1251
  }
1252
1252
  }
1253
1253
 
1254
- var formkitVersion = '202609021913';
1254
+ var formkitVersion = '202609030018';
1255
1255
 
1256
1256
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1257
1257
  // See LICENSE in the project root for license information.
@@ -1579,18 +1579,42 @@ class AuroRadioGroup extends i$2 {
1579
1579
  }
1580
1580
 
1581
1581
  if (changedProperties.has('validity')) {
1582
- if (this.validity && this.validity !== 'valid') {
1583
- this.items.forEach((el) => {
1584
- el.setAttribute('error', true);
1585
- el.setAttribute('aria-invalid', 'true');
1586
- });
1582
+ this.syncItemValidity();
1583
+ }
1584
+ }
1585
+
1586
+ /**
1587
+ * Whether the group is currently in an invalid state.
1588
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1589
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1590
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1591
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1592
+ * @private
1593
+ * @returns {boolean}
1594
+ */
1595
+ get isInvalid() {
1596
+ return Boolean(this.validity && this.validity !== 'valid');
1597
+ }
1598
+
1599
+ /**
1600
+ * Method for mirroring the group's invalid state onto each radio input.
1601
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1602
+ * reconnect can happen without `validity` itself changing.
1603
+ * @private
1604
+ * @returns {void}
1605
+ */
1606
+ syncItemValidity() {
1607
+ const invalid = this.isInvalid;
1608
+
1609
+ this.items.forEach((el) => {
1610
+ if (invalid) {
1611
+ el.setAttribute('error', true);
1612
+ el.setAttribute('aria-invalid', 'true');
1587
1613
  } else {
1588
- this.items.forEach((el) => {
1589
- el.removeAttribute('error');
1590
- el.removeAttribute('aria-invalid');
1591
- });
1614
+ el.removeAttribute('error');
1615
+ el.removeAttribute('aria-invalid');
1592
1616
  }
1593
- }
1617
+ });
1594
1618
  }
1595
1619
 
1596
1620
  /**
@@ -1646,8 +1670,9 @@ class AuroRadioGroup extends i$2 {
1646
1670
 
1647
1671
  this.items.forEach((el) => {
1648
1672
  el.required = this.required;
1649
- el.error = Boolean(this.error);
1650
1673
  });
1674
+
1675
+ this.syncItemValidity();
1651
1676
  }
1652
1677
 
1653
1678
  /**
@@ -1796,7 +1821,7 @@ class AuroRadioGroup extends i$2 {
1796
1821
  class="${e(groupClasses)}"
1797
1822
  part="radio-group"
1798
1823
  role="radiogroup"
1799
- aria-invalid="${o$1(this.validity && this.validity !== 'valid' ? 'true' : undefined)}"
1824
+ aria-invalid="${o$1(this.isInvalid ? 'true' : undefined)}"
1800
1825
  aria-describedby="${this.uniqueId}"
1801
1826
  >
1802
1827
  <legend class="${e(legendClasses)}">
@@ -1806,7 +1831,7 @@ class AuroRadioGroup extends i$2 {
1806
1831
  <slot @slotchange=${this.handleSlotChange}></slot>
1807
1832
  </fieldset>
1808
1833
 
1809
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1834
+ ${!this.isInvalid
1810
1835
  ? u`
1811
1836
  <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1812
1837
  <slot name="helpText"></slot>
@@ -1251,7 +1251,7 @@ class AuroHelpText extends i$2 {
1251
1251
  }
1252
1252
  }
1253
1253
 
1254
- var formkitVersion = '202609021913';
1254
+ var formkitVersion = '202609030018';
1255
1255
 
1256
1256
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1257
1257
  // See LICENSE in the project root for license information.
@@ -1579,18 +1579,42 @@ class AuroRadioGroup extends i$2 {
1579
1579
  }
1580
1580
 
1581
1581
  if (changedProperties.has('validity')) {
1582
- if (this.validity && this.validity !== 'valid') {
1583
- this.items.forEach((el) => {
1584
- el.setAttribute('error', true);
1585
- el.setAttribute('aria-invalid', 'true');
1586
- });
1582
+ this.syncItemValidity();
1583
+ }
1584
+ }
1585
+
1586
+ /**
1587
+ * Whether the group is currently in an invalid state.
1588
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1589
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1590
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1591
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1592
+ * @private
1593
+ * @returns {boolean}
1594
+ */
1595
+ get isInvalid() {
1596
+ return Boolean(this.validity && this.validity !== 'valid');
1597
+ }
1598
+
1599
+ /**
1600
+ * Method for mirroring the group's invalid state onto each radio input.
1601
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1602
+ * reconnect can happen without `validity` itself changing.
1603
+ * @private
1604
+ * @returns {void}
1605
+ */
1606
+ syncItemValidity() {
1607
+ const invalid = this.isInvalid;
1608
+
1609
+ this.items.forEach((el) => {
1610
+ if (invalid) {
1611
+ el.setAttribute('error', true);
1612
+ el.setAttribute('aria-invalid', 'true');
1587
1613
  } else {
1588
- this.items.forEach((el) => {
1589
- el.removeAttribute('error');
1590
- el.removeAttribute('aria-invalid');
1591
- });
1614
+ el.removeAttribute('error');
1615
+ el.removeAttribute('aria-invalid');
1592
1616
  }
1593
- }
1617
+ });
1594
1618
  }
1595
1619
 
1596
1620
  /**
@@ -1646,8 +1670,9 @@ class AuroRadioGroup extends i$2 {
1646
1670
 
1647
1671
  this.items.forEach((el) => {
1648
1672
  el.required = this.required;
1649
- el.error = Boolean(this.error);
1650
1673
  });
1674
+
1675
+ this.syncItemValidity();
1651
1676
  }
1652
1677
 
1653
1678
  /**
@@ -1796,7 +1821,7 @@ class AuroRadioGroup extends i$2 {
1796
1821
  class="${e(groupClasses)}"
1797
1822
  part="radio-group"
1798
1823
  role="radiogroup"
1799
- aria-invalid="${o$1(this.validity && this.validity !== 'valid' ? 'true' : undefined)}"
1824
+ aria-invalid="${o$1(this.isInvalid ? 'true' : undefined)}"
1800
1825
  aria-describedby="${this.uniqueId}"
1801
1826
  >
1802
1827
  <legend class="${e(legendClasses)}">
@@ -1806,7 +1831,7 @@ class AuroRadioGroup extends i$2 {
1806
1831
  <slot @slotchange=${this.handleSlotChange}></slot>
1807
1832
  </fieldset>
1808
1833
 
1809
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1834
+ ${!this.isInvalid
1810
1835
  ? u`
1811
1836
  <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1812
1837
  <slot name="helpText"></slot>
@@ -1251,7 +1251,7 @@ class AuroHelpText extends i$2 {
1251
1251
  }
1252
1252
  }
1253
1253
 
1254
- var formkitVersion = '202609021913';
1254
+ var formkitVersion = '202609030018';
1255
1255
 
1256
1256
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1257
1257
  // See LICENSE in the project root for license information.
@@ -1579,18 +1579,42 @@ class AuroRadioGroup extends i$2 {
1579
1579
  }
1580
1580
 
1581
1581
  if (changedProperties.has('validity')) {
1582
- if (this.validity && this.validity !== 'valid') {
1583
- this.items.forEach((el) => {
1584
- el.setAttribute('error', true);
1585
- el.setAttribute('aria-invalid', 'true');
1586
- });
1582
+ this.syncItemValidity();
1583
+ }
1584
+ }
1585
+
1586
+ /**
1587
+ * Whether the group is currently in an invalid state.
1588
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1589
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1590
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1591
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1592
+ * @private
1593
+ * @returns {boolean}
1594
+ */
1595
+ get isInvalid() {
1596
+ return Boolean(this.validity && this.validity !== 'valid');
1597
+ }
1598
+
1599
+ /**
1600
+ * Method for mirroring the group's invalid state onto each radio input.
1601
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1602
+ * reconnect can happen without `validity` itself changing.
1603
+ * @private
1604
+ * @returns {void}
1605
+ */
1606
+ syncItemValidity() {
1607
+ const invalid = this.isInvalid;
1608
+
1609
+ this.items.forEach((el) => {
1610
+ if (invalid) {
1611
+ el.setAttribute('error', true);
1612
+ el.setAttribute('aria-invalid', 'true');
1587
1613
  } else {
1588
- this.items.forEach((el) => {
1589
- el.removeAttribute('error');
1590
- el.removeAttribute('aria-invalid');
1591
- });
1614
+ el.removeAttribute('error');
1615
+ el.removeAttribute('aria-invalid');
1592
1616
  }
1593
- }
1617
+ });
1594
1618
  }
1595
1619
 
1596
1620
  /**
@@ -1646,8 +1670,9 @@ class AuroRadioGroup extends i$2 {
1646
1670
 
1647
1671
  this.items.forEach((el) => {
1648
1672
  el.required = this.required;
1649
- el.error = Boolean(this.error);
1650
1673
  });
1674
+
1675
+ this.syncItemValidity();
1651
1676
  }
1652
1677
 
1653
1678
  /**
@@ -1796,7 +1821,7 @@ class AuroRadioGroup extends i$2 {
1796
1821
  class="${e(groupClasses)}"
1797
1822
  part="radio-group"
1798
1823
  role="radiogroup"
1799
- aria-invalid="${o$1(this.validity && this.validity !== 'valid' ? 'true' : undefined)}"
1824
+ aria-invalid="${o$1(this.isInvalid ? 'true' : undefined)}"
1800
1825
  aria-describedby="${this.uniqueId}"
1801
1826
  >
1802
1827
  <legend class="${e(legendClasses)}">
@@ -1806,7 +1831,7 @@ class AuroRadioGroup extends i$2 {
1806
1831
  <slot @slotchange=${this.handleSlotChange}></slot>
1807
1832
  </fieldset>
1808
1833
 
1809
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1834
+ ${!this.isInvalid
1810
1835
  ? u`
1811
1836
  <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1812
1837
  <slot name="helpText"></slot>
@@ -186,6 +186,24 @@ export class AuroRadioGroup extends LitElement {
186
186
  * @returns {void}
187
187
  */
188
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;
189
207
  /**
190
208
  * Resets component to initial state.
191
209
  * @returns {void}
@@ -1190,7 +1190,7 @@ class AuroHelpText extends LitElement {
1190
1190
  }
1191
1191
  }
1192
1192
 
1193
- var formkitVersion = '202609021913';
1193
+ var formkitVersion = '202609030018';
1194
1194
 
1195
1195
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1196
1196
  // See LICENSE in the project root for license information.
@@ -1518,18 +1518,42 @@ class AuroRadioGroup extends LitElement {
1518
1518
  }
1519
1519
 
1520
1520
  if (changedProperties.has('validity')) {
1521
- if (this.validity && this.validity !== 'valid') {
1522
- this.items.forEach((el) => {
1523
- el.setAttribute('error', true);
1524
- el.setAttribute('aria-invalid', 'true');
1525
- });
1521
+ this.syncItemValidity();
1522
+ }
1523
+ }
1524
+
1525
+ /**
1526
+ * Whether the group is currently in an invalid state.
1527
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1528
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1529
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1530
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1531
+ * @private
1532
+ * @returns {boolean}
1533
+ */
1534
+ get isInvalid() {
1535
+ return Boolean(this.validity && this.validity !== 'valid');
1536
+ }
1537
+
1538
+ /**
1539
+ * Method for mirroring the group's invalid state onto each radio input.
1540
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1541
+ * reconnect can happen without `validity` itself changing.
1542
+ * @private
1543
+ * @returns {void}
1544
+ */
1545
+ syncItemValidity() {
1546
+ const invalid = this.isInvalid;
1547
+
1548
+ this.items.forEach((el) => {
1549
+ if (invalid) {
1550
+ el.setAttribute('error', true);
1551
+ el.setAttribute('aria-invalid', 'true');
1526
1552
  } else {
1527
- this.items.forEach((el) => {
1528
- el.removeAttribute('error');
1529
- el.removeAttribute('aria-invalid');
1530
- });
1553
+ el.removeAttribute('error');
1554
+ el.removeAttribute('aria-invalid');
1531
1555
  }
1532
- }
1556
+ });
1533
1557
  }
1534
1558
 
1535
1559
  /**
@@ -1585,8 +1609,9 @@ class AuroRadioGroup extends LitElement {
1585
1609
 
1586
1610
  this.items.forEach((el) => {
1587
1611
  el.required = this.required;
1588
- el.error = Boolean(this.error);
1589
1612
  });
1613
+
1614
+ this.syncItemValidity();
1590
1615
  }
1591
1616
 
1592
1617
  /**
@@ -1735,7 +1760,7 @@ class AuroRadioGroup extends LitElement {
1735
1760
  class="${classMap(groupClasses)}"
1736
1761
  part="radio-group"
1737
1762
  role="radiogroup"
1738
- aria-invalid="${ifDefined(this.validity && this.validity !== 'valid' ? 'true' : undefined)}"
1763
+ aria-invalid="${ifDefined(this.isInvalid ? 'true' : undefined)}"
1739
1764
  aria-describedby="${this.uniqueId}"
1740
1765
  >
1741
1766
  <legend class="${classMap(legendClasses)}">
@@ -1745,7 +1770,7 @@ class AuroRadioGroup extends LitElement {
1745
1770
  <slot @slotchange=${this.handleSlotChange}></slot>
1746
1771
  </fieldset>
1747
1772
 
1748
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1773
+ ${!this.isInvalid
1749
1774
  ? html$1`
1750
1775
  <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1751
1776
  <slot name="helpText"></slot>
@@ -1190,7 +1190,7 @@ class AuroHelpText extends LitElement {
1190
1190
  }
1191
1191
  }
1192
1192
 
1193
- var formkitVersion = '202609021913';
1193
+ var formkitVersion = '202609030018';
1194
1194
 
1195
1195
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1196
1196
  // See LICENSE in the project root for license information.
@@ -1518,18 +1518,42 @@ class AuroRadioGroup extends LitElement {
1518
1518
  }
1519
1519
 
1520
1520
  if (changedProperties.has('validity')) {
1521
- if (this.validity && this.validity !== 'valid') {
1522
- this.items.forEach((el) => {
1523
- el.setAttribute('error', true);
1524
- el.setAttribute('aria-invalid', 'true');
1525
- });
1521
+ this.syncItemValidity();
1522
+ }
1523
+ }
1524
+
1525
+ /**
1526
+ * Whether the group is currently in an invalid state.
1527
+ * `validity` — not `error` — is the authoritative source: `validate()` resolves the
1528
+ * `error` attribute to `validity = 'customError'`, so `error` is already covered here.
1529
+ * Single definition of "invalid" for the whole component, consumed by `render()` and
1530
+ * `syncItemValidity()` so the fieldset and its children can never disagree.
1531
+ * @private
1532
+ * @returns {boolean}
1533
+ */
1534
+ get isInvalid() {
1535
+ return Boolean(this.validity && this.validity !== 'valid');
1536
+ }
1537
+
1538
+ /**
1539
+ * Method for mirroring the group's invalid state onto each radio input.
1540
+ * Has to be re-applied from `handleItems()` as well, because a slot change or a
1541
+ * reconnect can happen without `validity` itself changing.
1542
+ * @private
1543
+ * @returns {void}
1544
+ */
1545
+ syncItemValidity() {
1546
+ const invalid = this.isInvalid;
1547
+
1548
+ this.items.forEach((el) => {
1549
+ if (invalid) {
1550
+ el.setAttribute('error', true);
1551
+ el.setAttribute('aria-invalid', 'true');
1526
1552
  } else {
1527
- this.items.forEach((el) => {
1528
- el.removeAttribute('error');
1529
- el.removeAttribute('aria-invalid');
1530
- });
1553
+ el.removeAttribute('error');
1554
+ el.removeAttribute('aria-invalid');
1531
1555
  }
1532
- }
1556
+ });
1533
1557
  }
1534
1558
 
1535
1559
  /**
@@ -1585,8 +1609,9 @@ class AuroRadioGroup extends LitElement {
1585
1609
 
1586
1610
  this.items.forEach((el) => {
1587
1611
  el.required = this.required;
1588
- el.error = Boolean(this.error);
1589
1612
  });
1613
+
1614
+ this.syncItemValidity();
1590
1615
  }
1591
1616
 
1592
1617
  /**
@@ -1735,7 +1760,7 @@ class AuroRadioGroup extends LitElement {
1735
1760
  class="${classMap(groupClasses)}"
1736
1761
  part="radio-group"
1737
1762
  role="radiogroup"
1738
- aria-invalid="${ifDefined(this.validity && this.validity !== 'valid' ? 'true' : undefined)}"
1763
+ aria-invalid="${ifDefined(this.isInvalid ? 'true' : undefined)}"
1739
1764
  aria-describedby="${this.uniqueId}"
1740
1765
  >
1741
1766
  <legend class="${classMap(legendClasses)}">
@@ -1745,7 +1770,7 @@ class AuroRadioGroup extends LitElement {
1745
1770
  <slot @slotchange=${this.handleSlotChange}></slot>
1746
1771
  </fieldset>
1747
1772
 
1748
- ${!this.validity || this.validity === undefined || this.validity === 'valid'
1773
+ ${!this.isInvalid
1749
1774
  ? html$1`
1750
1775
  <${this.helpTextTag} id="${this.uniqueId}" appearance="${this.onDark ? 'inverse' : this.appearance}" part="helpText">
1751
1776
  <slot name="helpText"></slot>