@aurodesignsystem-dev/auro-formkit 0.0.0-pr1488.1 → 0.0.0-pr1489.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 (102) hide show
  1. package/components/bibtemplate/dist/auro-bibtemplate.d.ts +7 -0
  2. package/components/bibtemplate/dist/index.js +9 -1
  3. package/components/bibtemplate/dist/registered.js +9 -1
  4. package/components/checkbox/demo/customize.min.js +1 -1
  5. package/components/checkbox/demo/getting-started.min.js +1 -1
  6. package/components/checkbox/demo/index.min.js +1 -1
  7. package/components/checkbox/demo/pages.json +1 -1
  8. package/components/checkbox/demo/why-checkbox.html +57 -0
  9. package/components/checkbox/demo/why-checkbox.md +86 -0
  10. package/components/checkbox/dist/index.js +1 -1
  11. package/components/checkbox/dist/registered.js +1 -1
  12. package/components/combobox/demo/customize.min.js +234 -16
  13. package/components/combobox/demo/getting-started.min.js +234 -16
  14. package/components/combobox/demo/index.min.js +234 -16
  15. package/components/combobox/demo/pages.json +1 -1
  16. package/components/combobox/demo/why-combobox.html +57 -0
  17. package/components/combobox/demo/why-combobox.md +113 -0
  18. package/components/combobox/dist/index.js +234 -16
  19. package/components/combobox/dist/registered.js +234 -16
  20. package/components/counter/demo/customize.min.js +233 -15
  21. package/components/counter/demo/index.min.js +233 -15
  22. package/components/counter/demo/keyboard-behavior.md +1 -0
  23. package/components/counter/demo/pages.json +1 -1
  24. package/components/counter/demo/why-counter.html +57 -0
  25. package/components/counter/demo/why-counter.md +108 -0
  26. package/components/counter/dist/index.js +10 -2
  27. package/components/counter/dist/registered.js +10 -2
  28. package/components/datepicker/demo/accessibility.md +51 -3
  29. package/components/datepicker/demo/api.md +11 -2
  30. package/components/datepicker/demo/customize.html +2 -0
  31. package/components/datepicker/demo/customize.js +19 -0
  32. package/components/datepicker/demo/customize.md +72 -8
  33. package/components/datepicker/demo/customize.min.js +26029 -0
  34. package/components/datepicker/demo/design.md +3 -1
  35. package/components/datepicker/demo/index.js +5 -1
  36. package/components/datepicker/demo/index.md +83 -2
  37. package/components/datepicker/demo/index.min.js +1564 -96
  38. package/components/datepicker/demo/keyboard-behavior.md +201 -2
  39. package/components/datepicker/demo/pages.json +1 -1
  40. package/components/datepicker/demo/voiceover.md +19 -12
  41. package/components/datepicker/demo/why-datepicker.html +57 -0
  42. package/components/datepicker/demo/why-datepicker.md +133 -0
  43. package/components/datepicker/dist/index.js +1489 -97
  44. package/components/datepicker/dist/registered.js +1489 -97
  45. package/components/datepicker/dist/src/auro-calendar-cell.d.ts +66 -1
  46. package/components/datepicker/dist/src/auro-calendar-month.d.ts +28 -0
  47. package/components/datepicker/dist/src/auro-calendar.d.ts +100 -0
  48. package/components/datepicker/dist/src/auro-datepicker.d.ts +88 -0
  49. package/components/datepicker/dist/src/datepickerKeyboardStrategy.d.ts +5 -3
  50. package/components/dropdown/demo/accessibility.md +11 -0
  51. package/components/dropdown/demo/api.md +1 -0
  52. package/components/dropdown/demo/customize.md +3 -0
  53. package/components/dropdown/demo/customize.min.js +223 -13
  54. package/components/dropdown/demo/getting-started.min.js +223 -13
  55. package/components/dropdown/demo/index.min.js +223 -13
  56. package/components/dropdown/demo/keyboard-behavior.md +1 -0
  57. package/components/dropdown/demo/pages.json +1 -1
  58. package/components/dropdown/demo/why-dropdown.html +57 -0
  59. package/components/dropdown/demo/why-dropdown.md +97 -0
  60. package/components/dropdown/dist/auro-dropdown.d.ts +33 -1
  61. package/components/dropdown/dist/index.js +223 -13
  62. package/components/dropdown/dist/registered.js +223 -13
  63. package/components/form/demo/customize.min.js +2191 -145
  64. package/components/form/demo/getting-started.min.js +2191 -145
  65. package/components/form/demo/index.min.js +2191 -145
  66. package/components/form/demo/pages.json +1 -1
  67. package/components/form/demo/registerDemoDeps.min.js +2191 -145
  68. package/components/form/demo/why-form.html +57 -0
  69. package/components/form/demo/why-form.md +101 -0
  70. package/components/input/demo/customize.min.js +1 -1
  71. package/components/input/demo/getting-started.min.js +1 -1
  72. package/components/input/demo/index.min.js +1 -1
  73. package/components/input/demo/pages.json +1 -1
  74. package/components/input/demo/why-input.html +57 -0
  75. package/components/input/demo/why-input.md +121 -0
  76. package/components/input/dist/index.js +1 -1
  77. package/components/input/dist/registered.js +1 -1
  78. package/components/menu/demo/pages.json +1 -1
  79. package/components/menu/demo/why-menu.html +57 -0
  80. package/components/menu/demo/why-menu.md +104 -0
  81. package/components/radio/demo/customize.min.js +2186 -0
  82. package/components/radio/demo/demo-support.min.js +55807 -0
  83. package/components/radio/demo/getting-started.js +1 -1
  84. package/components/radio/demo/getting-started.md +1 -1
  85. package/components/radio/demo/getting-started.min.js +2205 -0
  86. package/components/radio/demo/index.min.js +1 -1
  87. package/components/radio/demo/pages.json +1 -1
  88. package/components/radio/demo/why-radio.html +57 -0
  89. package/components/radio/demo/why-radio.md +92 -0
  90. package/components/radio/dist/index.js +1 -1
  91. package/components/radio/dist/registered.js +1 -1
  92. package/components/select/demo/customize.min.js +233 -15
  93. package/components/select/demo/getting-started.min.js +233 -15
  94. package/components/select/demo/index.min.js +233 -15
  95. package/components/select/demo/keyboard-behavior.md +1 -0
  96. package/components/select/demo/pages.json +1 -1
  97. package/components/select/demo/why-select.html +57 -0
  98. package/components/select/demo/why-select.md +128 -0
  99. package/components/select/dist/index.js +233 -15
  100. package/components/select/dist/registered.js +233 -15
  101. package/custom-elements.json +2177 -1460
  102. package/package.json +2 -2
@@ -4662,7 +4662,7 @@ function applyKeyboardStrategy(component, strategy, options = {}) {
4662
4662
  });
4663
4663
  }
4664
4664
 
4665
- var styleCss$2$1 = i$7`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
4665
+ var styleCss$2$1 = i$7`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host([desktopmodal]:popover-open)::backdrop{background:transparent}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
4666
4666
 
4667
4667
  var colorCss$2$1 = i$7`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
4668
4668
 
@@ -5293,7 +5293,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
5293
5293
  }
5294
5294
  };
5295
5295
 
5296
- var formkitVersion$2 = '202605292326';
5296
+ var formkitVersion$2 = '202606011856';
5297
5297
 
5298
5298
  let AuroElement$2 = class AuroElement extends i$4 {
5299
5299
  static get properties() {
@@ -5473,6 +5473,7 @@ class AuroDropdown extends AuroElement$2 {
5473
5473
  _intializeDefaults() {
5474
5474
  this.appearance = 'default';
5475
5475
  this.chevron = false;
5476
+ this.desktopModal = false;
5476
5477
  this.disabled = false;
5477
5478
  this.disableKeyboardHandling = false;
5478
5479
  this.error = false;
@@ -5653,6 +5654,14 @@ class AuroDropdown extends AuroElement$2 {
5653
5654
  reflect: true
5654
5655
  },
5655
5656
 
5657
+ /**
5658
+ * If declared, the dropdown will behave as a modal dialog when in a desktop viewport size.
5659
+ */
5660
+ desktopModal: {
5661
+ type: Boolean,
5662
+ reflect: true
5663
+ },
5664
+
5656
5665
  /**
5657
5666
  * If declared, the dropdown will only show by calling the API .show() public method.
5658
5667
  */
@@ -5940,6 +5949,15 @@ class AuroDropdown extends AuroElement$2 {
5940
5949
 
5941
5950
  disconnectedCallback() {
5942
5951
  super.disconnectedCallback();
5952
+ this._clearPageInert();
5953
+ if (this._bibTabHandler) {
5954
+ this.removeEventListener('keydown', this._bibTabHandler);
5955
+ this._bibTabHandler = undefined;
5956
+ }
5957
+ if (this.focusTrap) {
5958
+ this.focusTrap.disconnect();
5959
+ this.focusTrap = undefined;
5960
+ }
5943
5961
  if (this.floater) {
5944
5962
  this.floater.hideBib('disconnect');
5945
5963
  this.floater.disconnect();
@@ -5967,19 +5985,45 @@ class AuroDropdown extends AuroElement$2 {
5967
5985
  if (this.isPopoverVisible) {
5968
5986
  // Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
5969
5987
  // Desktop: use show() for Floating UI positioning + FocusTrap for focus management
5970
- const useModal = this.isBibFullscreen;
5971
- this.bibElement.value.open(useModal);
5988
+ this.bibElement.value.open(this.isBibFullscreen);
5989
+ this.updateFocusTrap();
5990
+
5991
+ // Desktop modal: make siblings inert so content outside is not interactive
5992
+ if (this.desktopModal && !this.isBibFullscreen) {
5993
+ this._setPageInert();
5994
+ }
5972
5995
  } else {
5973
5996
  this.bibElement.value.close();
5997
+ this._clearPageInert();
5974
5998
  }
5975
5999
  }
5976
6000
 
5977
6001
  // When fullscreen strategy changes while open, re-open dialog with correct mode
5978
6002
  // (e.g. resizing from desktop → mobile while dropdown is open)
5979
6003
  if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
5980
- const useModal = this.isBibFullscreen;
5981
6004
  this.bibElement.value.close();
5982
- this.bibElement.value.open(useModal);
6005
+ this.bibElement.value.open(this.isBibFullscreen);
6006
+
6007
+ // Re-initialize focus management for the new strategy
6008
+ this.updateFocusTrap();
6009
+
6010
+ // Toggle inert: desktop modal needs it, fullscreen showModal() handles it natively
6011
+ if (this.desktopModal && !this.isBibFullscreen) {
6012
+ this._setPageInert();
6013
+ } else {
6014
+ this._clearPageInert();
6015
+ }
6016
+ }
6017
+
6018
+ // Handle desktopModal toggled while the dropdown is already open.
6019
+ // Re-initialize focus trapping and page inert state to match the new mode.
6020
+ if (changedProperties.has('desktopModal') && this.isPopoverVisible && !this.isBibFullscreen) {
6021
+ this.updateFocusTrap();
6022
+ if (this.desktopModal) {
6023
+ this._setPageInert();
6024
+ } else {
6025
+ this._clearPageInert();
6026
+ }
5983
6027
  }
5984
6028
  }
5985
6029
 
@@ -5989,8 +6033,14 @@ class AuroDropdown extends AuroElement$2 {
5989
6033
  * @param {CustomEvent} event - The custom event that contains the dropdown toggle information.
5990
6034
  */
5991
6035
  handleDropdownToggle(event) {
5992
- this.updateFocusTrap();
5993
6036
  this.isPopoverVisible = event.detail.expanded;
6037
+
6038
+ // Tear down FocusTrap when closing. Creation happens in updated()
6039
+ // after the dialog is open so getFocusableElements can find content.
6040
+ if (!this.isPopoverVisible) {
6041
+ this.updateFocusTrap();
6042
+ }
6043
+
5994
6044
  const eventType = event.detail.eventType || "unknown";
5995
6045
  if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
5996
6046
  this.trigger.focus();
@@ -6089,19 +6139,178 @@ class AuroDropdown extends AuroElement$2 {
6089
6139
  * @private
6090
6140
  */
6091
6141
  updateFocusTrap() {
6142
+ // Always clean up existing handlers/traps before setting up new ones
6143
+ // to prevent duplicate listeners on repeated calls.
6144
+ if (this._bibTabHandler) {
6145
+ this.removeEventListener('keydown', this._bibTabHandler);
6146
+ this._bibTabHandler = undefined;
6147
+ }
6148
+
6149
+ if (this.focusTrap) {
6150
+ this.focusTrap.disconnect();
6151
+ this.focusTrap = undefined;
6152
+ }
6153
+
6092
6154
  if (this.isPopoverVisible) {
6093
6155
  if (!this.isBibFullscreen) {
6094
- // Desktop: show() doesn't trap focus, so use FocusTrap
6095
- this.focusTrap = new FocusTrap(this.bibContent);
6096
- this.focusTrap.focusFirstElement();
6156
+ if (this.desktopModal) {
6157
+ // Desktop modal: trap focus only within the bib content.
6158
+ // Can't use FocusTrap on the bib element because keydown events
6159
+ // from slotted content bubble through the dropdown host (light DOM),
6160
+ // not through the bib (shadow projection target). Using FocusTrap
6161
+ // on the dropdown would include the trigger in the tab cycle.
6162
+ // Instead, listen for Tab on the dropdown and manually wrap focus
6163
+ // within the bib's focusable elements.
6164
+ this._bibTabHandler = (event) => {
6165
+ if (event.key !== 'Tab') {
6166
+ return;
6167
+ }
6168
+
6169
+ // Collect focusable elements from the bib content.
6170
+ const focusables = getFocusableElements(this.bibContent);
6171
+
6172
+ // Fallback: try from slotted content directly
6173
+ if (!focusables.length) {
6174
+ const slot = this.shadowRoot.querySelector('.slotContent slot');
6175
+ const assignedNodes = slot ? slot.assignedNodes({ flatten: true }) : [];
6176
+
6177
+ for (const node of assignedNodes) {
6178
+ if (node.nodeType === Node.ELEMENT_NODE) {
6179
+ focusables.push(...getFocusableElements(node));
6180
+ }
6181
+ }
6182
+ }
6183
+
6184
+ if (!focusables.length) {
6185
+ return;
6186
+ }
6187
+
6188
+ event.preventDefault();
6189
+
6190
+ const direction = event.shiftKey ? -1 : 1; // eslint-disable-line no-magic-numbers
6191
+
6192
+ // Walk the active element chain through shadow roots
6193
+ const actives = this._getActiveElements();
6194
+
6195
+ let idx = focusables.findIndex((el) => actives.includes(el));
6196
+
6197
+ if (idx === -1) { // eslint-disable-line no-magic-numbers
6198
+ // Focus is not on a known element — move to first/last
6199
+ idx = direction === 1 ? -1 : focusables.length; // eslint-disable-line no-magic-numbers
6200
+ }
6201
+
6202
+ // Try each element in order, skipping any that can't receive focus
6203
+ // (e.g. hidden elements, elements in collapsed sections)
6204
+ for (let index = 0; index < focusables.length; index++) { // eslint-disable-line no-plusplus
6205
+ let nextIdx = idx + direction;
6206
+
6207
+ // Wrap around
6208
+ if (nextIdx < 0) {
6209
+ nextIdx = focusables.length - 1;
6210
+ } else if (nextIdx >= focusables.length) {
6211
+ nextIdx = 0;
6212
+ }
6213
+
6214
+ focusables[nextIdx].focus();
6215
+
6216
+ // Verify focus actually moved to the target
6217
+ const newActives = this._getActiveElements();
6218
+
6219
+ if (newActives.includes(focusables[nextIdx])) {
6220
+ return;
6221
+ }
6222
+
6223
+ // Focus didn't stick — skip this element and try the next
6224
+ idx = nextIdx;
6225
+ }
6226
+ };
6227
+ this.addEventListener('keydown', this._bibTabHandler);
6228
+
6229
+ // Move initial focus into the bib content, matching FocusTrap behavior
6230
+ requestAnimationFrame(() => {
6231
+ const focusables = getFocusableElements(this.bibContent);
6232
+ if (focusables.length) {
6233
+ focusables[0].focus();
6234
+ }
6235
+ });
6236
+ } else {
6237
+ // Normal desktop: use FocusTrap on the bib element
6238
+ this.focusTrap = new FocusTrap(this.bibContent);
6239
+ this.focusTrap.focusFirstElement();
6240
+ }
6097
6241
  }
6098
6242
  // Fullscreen: showModal() provides native focus trapping
6243
+ }
6244
+ }
6245
+
6246
+ /**
6247
+ * Returns the chain of active (focused) elements through shadow roots.
6248
+ * @private
6249
+ * @returns {Array<HTMLElement>}
6250
+ */
6251
+ _getActiveElements() {
6252
+ let { activeElement } = document;
6253
+ const actives = [activeElement];
6254
+
6255
+ while (activeElement?.shadowRoot?.activeElement) {
6256
+ activeElement = activeElement.shadowRoot.activeElement;
6257
+ actives.push(activeElement);
6258
+ }
6259
+
6260
+ return actives;
6261
+ }
6262
+
6263
+ /**
6264
+ * Sets `inert` on sibling elements of the dropdown's top-level host
6265
+ * so that content outside the dropdown is not interactive while the modal is open.
6266
+ * Walks up through shadow DOM boundaries to find the outermost host element
6267
+ * in the light DOM, then sets `inert` on siblings at each ancestor level
6268
+ * to ensure all page content outside the host subtree is inert.
6269
+ * @private
6270
+ */
6271
+ _setPageInert() {
6272
+ if (this._inertSiblings) {
6099
6273
  return;
6100
6274
  }
6101
6275
 
6102
- if (this.focusTrap) {
6103
- this.focusTrap.disconnect();
6104
- this.focusTrap = undefined;
6276
+ this._inertSiblings = [];
6277
+
6278
+ // Walk up through shadow DOM boundaries to find the topmost host
6279
+ // element in the light DOM. For example, if this dropdown is inside
6280
+ // auro-datepicker's shadow DOM, we walk up to the datepicker element
6281
+ // so we set inert on its siblings — not on the datepicker itself.
6282
+ let host = this;
6283
+ while (host.getRootNode() instanceof ShadowRoot) {
6284
+ host = host.getRootNode().host;
6285
+ }
6286
+
6287
+ // Walk up the ancestor chain, inerting siblings at each level
6288
+ // to ensure the entire page outside the host subtree is inert.
6289
+ let current = host;
6290
+ while (current.parentElement) {
6291
+ const parent = current.parentElement;
6292
+ for (const sibling of parent.children) {
6293
+ if (sibling !== current) {
6294
+ this._inertSiblings.push({ element: sibling, wasInert: sibling.inert });
6295
+ sibling.inert = true;
6296
+ }
6297
+ }
6298
+ current = parent;
6299
+ }
6300
+ }
6301
+
6302
+ /**
6303
+ * Restores `inert` state on siblings that were tracked by `_setPageInert`.
6304
+ * Preserves the previous inert state so externally-inerted elements are
6305
+ * not inadvertently re-enabled.
6306
+ * @private
6307
+ */
6308
+ _clearPageInert() {
6309
+ if (this._inertSiblings) {
6310
+ for (const entry of this._inertSiblings) {
6311
+ entry.element.inert = entry.wasInert;
6312
+ }
6313
+ this._inertSiblings = undefined;
6105
6314
  }
6106
6315
  }
6107
6316
 
@@ -6340,6 +6549,7 @@ class AuroDropdown extends AuroElement$2 {
6340
6549
  shape="${this.shape}"
6341
6550
  ?data-show="${this.isPopoverVisible}"
6342
6551
  ?isfullscreen="${this.isBibFullscreen}"
6552
+ ?desktopmodal="${this.desktopModal}"
6343
6553
  .dialogLabel="${this.bibDialogLabel}"
6344
6554
  ${n$2(this.bibElement)}
6345
6555
  >
@@ -13045,7 +13255,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
13045
13255
  }
13046
13256
  };
13047
13257
 
13048
- var formkitVersion$1 = '202605292326';
13258
+ var formkitVersion$1 = '202606011856';
13049
13259
 
13050
13260
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
13051
13261
  // See LICENSE in the project root for license information.
@@ -13999,6 +14209,14 @@ class AuroBibtemplate extends i$4 {
13999
14209
  large: {
14000
14210
  type: Boolean,
14001
14211
  reflect: true
14212
+ },
14213
+
14214
+ /**
14215
+ * If declared, the footer slot will be rendered even when not in fullscreen mode.
14216
+ */
14217
+ showFooter: {
14218
+ type: Boolean,
14219
+ reflect: true
14002
14220
  }
14003
14221
  };
14004
14222
  }
@@ -14101,7 +14319,7 @@ class AuroBibtemplate extends i$4 {
14101
14319
  <slot></slot>
14102
14320
  </div>
14103
14321
 
14104
- ${this.isFullscreen ? u$7`
14322
+ ${this.isFullscreen || this.showFooter ? u$7`
14105
14323
  <div id="footerContainer">
14106
14324
  <slot name="footer"></slot>
14107
14325
  </div>` : null}
@@ -14110,7 +14328,7 @@ class AuroBibtemplate extends i$4 {
14110
14328
  }
14111
14329
  }
14112
14330
 
14113
- var formkitVersion = '202605292326';
14331
+ var formkitVersion = '202606011856';
14114
14332
 
14115
14333
  var styleCss$3 = i$7`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
14116
14334
 
@@ -1 +1 @@
1
- ["accessibility.md","api.md","customize.md","design.md","getting-started.md","index.md","keyboard-behavior.md","voiceover.md","readme.md"]
1
+ ["accessibility.md","api.md","customize.md","design.md","getting-started.md","index.md","keyboard-behavior.md","voiceover.md","why-combobox.md","readme.md"]
@@ -0,0 +1,57 @@
1
+ <!--
2
+ Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
3
+ See LICENSE in the project root for license information.
4
+
5
+ HTML in this document is standardized and NOT to be edited.
6
+ All demo code should be added/edited in ./demo/why-combobox.md
7
+
8
+ With the exception of adding custom elements if needed for the demo.
9
+
10
+ ----------------------- DO NOT EDIT -----------------------------
11
+
12
+ -->
13
+
14
+ <!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="UTF-8" />
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
19
+ <title>Auro Web Component Demo | auro-combobox | Why auro-combobox</title>
20
+
21
+ <!-- highlight.js Stylesheet -->
22
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github.min.css"/>
23
+
24
+ <!-- Legacy reference is still needed to support auro-combobox's use of legacy token values at this time -->
25
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@aurodesignsystem/design-tokens@latest/dist/legacy/auro-classic/CSSCustomProperties.css"/>
26
+
27
+ <!-- Design Token Alaska Theme -->
28
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@aurodesignsystem/design-tokens@latest/dist/themes/alaska/CSSCustomProperties--alaska.min.css"/>
29
+
30
+ <!-- Webcore Stylesheet Alaska Theme -->
31
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@aurodesignsystem/webcorestylesheets@latest/dist/bundled/themes/alaska.global.min.css" />
32
+
33
+ <!-- Demo Specific Styles -->
34
+ <link rel="stylesheet" type="text/css" href="./styles.min.css" />
35
+ <style>
36
+ table {
37
+ --ds-color-container-secondary-default: transparent;
38
+ }
39
+
40
+ tr:not(:last-of-type) {
41
+ border-bottom: 1px solid var(--ds-color-border-tertiary-default);
42
+ }
43
+ </style>
44
+ </head>
45
+ <body class="auro-markdown">
46
+ <main></main>
47
+
48
+ <script type="module">
49
+ import { renderPage } from './demo-support.min.js';
50
+ await renderPage('./why-combobox.md');
51
+ </script>
52
+
53
+ <!-- If additional elements are needed for the demo, add them here. -->
54
+ <script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-header@latest/+esm" type="module"></script>
55
+ <script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-hyperlink@latest/+esm" type="module"></script>
56
+ </body>
57
+ </html>
@@ -0,0 +1,113 @@
1
+ <auro-header level="1" id="overview">Why auro-combobox?</auro-header>
2
+ <p>The native <code>&lt;input list&gt;</code> with <code>&lt;datalist&gt;</code> provides a basic autocomplete experience, but it cannot be styled, has no concept of required selection, and offers no mobile-friendly layout. <code>auro-combobox</code> is a fully featured autocomplete and selection component designed for real-world use.</p>
3
+ <auro-header level="2" id="accessibility">Accessibility</auro-header>
4
+ <p>Native <code>&lt;datalist&gt;</code> support varies between browsers. Some announce suggestion counts, others do not. Keyboard behavior is inconsistent, and there is no standard way to communicate selection state to screen readers.</p>
5
+ <p><code>auro-combobox</code> provides:</p>
6
+ <ul>
7
+ <li><strong>ARIA combobox pattern</strong> — The input carries <code>aria-expanded</code>, <code>aria-owns</code>, and <code>aria-haspopup</code> to properly describe the relationship between the input and the suggestions list.</li>
8
+ <li><strong>Active descendant tracking</strong> — <code>aria-activedescendant</code> moves with keyboard navigation so screen readers announce the highlighted option without moving DOM focus.</li>
9
+ <li><strong>Live region announcements</strong> — Selections are announced via <code>aria-live="polite"</code>, and validation errors use <code>aria-live="assertive"</code>.</li>
10
+ <li><strong>Full keyboard navigation</strong> — Arrow keys navigate options, Enter selects, Escape closes, Home/End jump to boundaries. A dedicated keyboard strategy handles all interactions.</li>
11
+ </ul>
12
+ <auro-header level="2" id="dualBehaviorModes">Dual behavior modes</auro-header>
13
+ <p>Native <code>&lt;datalist&gt;</code> always allows freeform input. There is no way to restrict the user to only the provided options.</p>
14
+ <p><code>auro-combobox</code> supports two modes:</p>
15
+ <ul>
16
+ <li><strong>Suggestion mode</strong> (default) — The user can type any value. Suggestions are offered but not required.</li>
17
+ <li><strong>Filter mode</strong> — The user must select from the available options. Typed text filters the list but cannot be submitted as a value. Validation enforces this constraint.</li>
18
+ </ul>
19
+ <auro-header level="2" id="realtimeFiltering">Real-time filtering</auro-header>
20
+ <p><code>&lt;datalist&gt;</code> filtering is browser-controlled and cannot be customized. Some browsers match from the start of the option text, others match anywhere.</p>
21
+ <p><code>auro-combobox</code> filters options as the user types, with full control:</p>
22
+ <ul>
23
+ <li><code>noFilter</code> disables filtering to show all options regardless of input</li>
24
+ <li><code>matchWord</code> highlights the matched portion of each option</li>
25
+ <li><code>persistInput</code> keeps the filter text visible after selection</li>
26
+ </ul>
27
+ <auro-header level="2" id="responsiveLayout">Responsive layout</auro-header>
28
+ <p>Native <code>&lt;datalist&gt;</code> renders a small browser-controlled popup that cannot be repositioned or resized.</p>
29
+ <p><code>auro-combobox</code> adapts to the viewport:</p>
30
+ <ul>
31
+ <li><strong>Desktop</strong> — Suggestions appear as a positioned dropdown using Floating UI, with configurable placement, offset, flip, and shift behavior</li>
32
+ <li><strong>Mobile</strong> — Suggestions open in a fullscreen dialog via <code>showModal()</code>, with a configurable breakpoint (<code>fullscreenBreakpoint</code>)</li>
33
+ <li><strong>Width matching</strong> — The dropdown can match the input width or size independently</li>
34
+ </ul>
35
+ <auro-header level="2" id="validation">Validation</auro-header>
36
+ <p>Native <code>&lt;datalist&gt;</code> has no built-in validation beyond standard <code>required</code>.</p>
37
+ <p><code>auro-combobox</code> integrates with the Auro form validation system:</p>
38
+ <ul>
39
+ <li>Required field validation with mode-aware messaging (separate messages for suggestion vs. filter mode)</li>
40
+ <li>Custom error messages per validity state (<code>setCustomValidityCustomError</code>, <code>setCustomValidityValueMissing</code>, <code>setCustomValidityValueMissingFilter</code>)</li>
41
+ <li>Validation on blur with <code>noValidate</code> opt-out</li>
42
+ <li>Error display via help text with <code>role="alert"</code></li>
43
+ </ul>
44
+ <auro-header level="2" id="inputMasking">Input masking</auro-header>
45
+ <p><code>&lt;datalist&gt;</code> inputs have no formatting support.</p>
46
+ <p><code>auro-combobox</code> supports input masks via the <code>format</code> attribute, enabling structured input (e.g., dates, phone numbers) while still offering suggestions.</p>
47
+ <auro-header level="2" id="designSystemIntegration">Design system integration</auro-header>
48
+ <p><code>&lt;datalist&gt;</code> styling is entirely browser-controlled. The popup cannot be themed, and option rendering is limited to plain text.</p>
49
+ <p><code>auro-combobox</code> is built with the Auro Design System:</p>
50
+ <ul>
51
+ <li>Three layout options: classic, emphasized, and snowflake</li>
52
+ <li>Light and dark theme support (<code>appearance</code>)</li>
53
+ <li>Checkmarks on selected options</li>
54
+ <li>Rich HTML content in options (icons, descriptions, nested structure)</li>
55
+ <li>CSS <code>::part()</code> selectors for styling</li>
56
+ </ul>
57
+ <auro-header level="2" id="summary">Summary</auro-header>
58
+ <table>
59
+ <thead>
60
+ <tr>
61
+ <th>Capability</th>
62
+ <th><code>&lt;input list&gt;</code> + <code>&lt;datalist&gt;</code></th>
63
+ <th><code>auro-combobox</code></th>
64
+ </tr>
65
+ </thead>
66
+ <tbody>
67
+ <tr>
68
+ <td>Restrict to options only</td>
69
+ <td>No</td>
70
+ <td>Yes (filter mode)</td>
71
+ </tr>
72
+ <tr>
73
+ <td>Real-time filtering control</td>
74
+ <td>Browser-controlled</td>
75
+ <td>Fully configurable</td>
76
+ </tr>
77
+ <tr>
78
+ <td>Keyboard navigation</td>
79
+ <td>Inconsistent</td>
80
+ <td>Full arrow/Enter/Escape/Home/End</td>
81
+ </tr>
82
+ <tr>
83
+ <td>Screen reader announcements</td>
84
+ <td>Inconsistent</td>
85
+ <td>Live regions and active descendant</td>
86
+ </tr>
87
+ <tr>
88
+ <td>Mobile fullscreen</td>
89
+ <td>No</td>
90
+ <td>Automatic at breakpoint</td>
91
+ </tr>
92
+ <tr>
93
+ <td>Input masking</td>
94
+ <td>No</td>
95
+ <td>Yes (format attribute)</td>
96
+ </tr>
97
+ <tr>
98
+ <td>Custom validation messages</td>
99
+ <td>No</td>
100
+ <td>Per-constraint messages</td>
101
+ </tr>
102
+ <tr>
103
+ <td>Rich option content</td>
104
+ <td>Plain text only</td>
105
+ <td>Full HTML</td>
106
+ </tr>
107
+ <tr>
108
+ <td>Theming</td>
109
+ <td>No</td>
110
+ <td>Three layouts + appearance modes</td>
111
+ </tr>
112
+ </tbody>
113
+ </table>