@hortonstudio/main 1.9.10 → 1.9.20
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.
- package/.prettierrc +8 -0
- package/README.md +146 -0
- package/eslint.config.js +32 -0
- package/index.ts +275 -0
- package/package.json +19 -2
- package/public/bootstrap.js +16 -0
- package/src/animations/animations.ts +93 -0
- package/src/animations/functions/counter/counter.ts +137 -0
- package/src/config.json +570 -0
- package/src/config.ts +105 -0
- package/src/modules/default/README.md +167 -0
- package/src/modules/default/default.ts +71 -0
- package/{autoInit → src/modules/default/functions}/accessibility/README.md +44 -12
- package/src/modules/default/functions/accessibility/accessibility.ts +54 -0
- package/src/modules/default/functions/accordion/README.md +451 -0
- package/src/modules/default/functions/accordion/accordion.ts +189 -0
- package/src/modules/default/functions/comparison/comparison.ts +424 -0
- package/src/modules/default/functions/marquee/marquee.ts +206 -0
- package/src/modules/default/functions/navbar/README.md +393 -0
- package/src/modules/default/functions/navbar/functions/arrow-navigation/arrow-navigation.ts +183 -0
- package/src/modules/default/functions/navbar/functions/dropdown/dropdown.ts +313 -0
- package/src/modules/default/functions/navbar/functions/menu/menu.ts +315 -0
- package/src/modules/default/functions/navbar/navbar.ts +51 -0
- package/{autoInit → src/modules/default/functions}/smooth-scroll/README.md +45 -14
- package/{autoInit/smooth-scroll/smooth-scroll.js → src/modules/default/functions/smooth-scroll/smooth-scroll.ts} +33 -38
- package/{autoInit → src/modules/default/functions}/transition/README.md +59 -32
- package/src/modules/default/functions/transition/transition.ts +290 -0
- package/src/modules/normalize/README.md +172 -0
- package/src/modules/normalize/functions/clickable/README.md +84 -0
- package/src/modules/normalize/functions/clickable/clickable.ts +43 -0
- package/src/modules/normalize/functions/clickable/functions/normalize/README.md +213 -0
- package/src/modules/normalize/functions/clickable/functions/normalize/normalize.ts +68 -0
- package/src/modules/normalize/functions/dupe/README.md +405 -0
- package/src/modules/normalize/functions/dupe/dupe.ts +197 -0
- package/src/modules/normalize/functions/sync/sync.ts +378 -0
- package/src/modules/normalize/normalize.ts +58 -0
- package/src/modules/structure/README.md +190 -0
- package/src/modules/structure/functions/form/README.md +94 -0
- package/src/modules/structure/functions/form/form.ts +54 -0
- package/src/modules/structure/functions/form/functions/honeypot/README.md +77 -0
- package/src/modules/structure/functions/form/functions/honeypot/honeypot.ts +37 -0
- package/src/modules/structure/functions/form/functions/range/README.md +410 -0
- package/src/modules/structure/functions/form/functions/range/range.ts +92 -0
- package/src/modules/structure/functions/form/functions/select/README.md +393 -0
- package/src/modules/structure/functions/form/functions/select/functions/custom-select/custom-select.ts +637 -0
- package/src/modules/structure/functions/form/functions/select/functions/states/states.ts +118 -0
- package/src/modules/structure/functions/form/functions/select/select.ts +48 -0
- package/src/modules/structure/functions/form/functions/test/test.ts +132 -0
- package/src/modules/structure/functions/pagination/README.md +527 -0
- package/src/modules/structure/functions/pagination/pagination.ts +493 -0
- package/src/modules/structure/functions/site-settings/README.md +395 -0
- package/src/modules/structure/functions/site-settings/site-settings.ts +158 -0
- package/{autoInit/accessibility → src/modules/structure}/functions/toc/README.md +18 -15
- package/{autoInit/accessibility/functions/toc/toc.js → src/modules/structure/functions/toc/functions/heading-links/heading-links.ts} +43 -63
- package/src/modules/structure/functions/toc/functions/progress-bar/progress-bar.ts +101 -0
- package/src/modules/structure/functions/toc/toc.ts +35 -0
- package/{autoInit/accessibility → src/modules/structure}/functions/year-replacement/README.md +7 -6
- package/src/modules/structure/functions/year-replacement/year-replacement.ts +59 -0
- package/src/modules/structure/structure.ts +59 -0
- package/src/utils/attributeSelector.ts +78 -0
- package/src/utils/cssVariables.ts +24 -0
- package/src/utils/gsap.ts +198 -0
- package/src/utils/heightAnimator.ts +130 -0
- package/src/utils/modalManager.ts +150 -0
- package/src/utils.ts +54 -0
- package/tsconfig.json +24 -0
- package/vite.config.js +45 -0
- package/.claude/settings.local.json +0 -70
- package/archive/hero.js +0 -794
- package/archive/modal.js +0 -80
- package/archive/text.js +0 -628
- package/autoInit/accessibility/accessibility.js +0 -53
- package/autoInit/accessibility/functions/blog-remover/README.md +0 -61
- package/autoInit/accessibility/functions/blog-remover/blog-remover.js +0 -31
- package/autoInit/accessibility/functions/click-forwarding/README.md +0 -60
- package/autoInit/accessibility/functions/click-forwarding/click-forwarding.js +0 -82
- package/autoInit/accessibility/functions/dropdown/README.md +0 -212
- package/autoInit/accessibility/functions/dropdown/dropdown.js +0 -167
- package/autoInit/accessibility/functions/list-accessibility/README.md +0 -56
- package/autoInit/accessibility/functions/list-accessibility/list-accessibility.js +0 -23
- package/autoInit/accessibility/functions/pagination/README.md +0 -428
- package/autoInit/accessibility/functions/pagination/pagination.js +0 -359
- package/autoInit/accessibility/functions/text-synchronization/README.md +0 -62
- package/autoInit/accessibility/functions/text-synchronization/text-synchronization.js +0 -101
- package/autoInit/accessibility/functions/year-replacement/year-replacement.js +0 -43
- package/autoInit/button/README.md +0 -122
- package/autoInit/button/button.js +0 -51
- package/autoInit/counter/README.md +0 -274
- package/autoInit/counter/counter.js +0 -185
- package/autoInit/form/README.md +0 -338
- package/autoInit/form/form.js +0 -374
- package/autoInit/navbar/README.md +0 -366
- package/autoInit/navbar/navbar.js +0 -786
- package/autoInit/site-settings/README.md +0 -218
- package/autoInit/site-settings/site-settings.js +0 -134
- package/autoInit/transition/transition.js +0 -116
- package/index.js +0 -305
- package/utils/before-after/README.md +0 -520
- package/utils/before-after/before-after.js +0 -653
- package/utils/css-animations/buttons/main/bgbasic/btn-main-bgbasic.html +0 -10
- package/utils/css-animations/buttons/main/bgfill/btn-main-bgfill.html +0 -29
- package/utils/css-animations/buttons/navbar/bgbasic/navbar-main-bgbasic.html +0 -17
- package/utils/css-animations/buttons/navbar/bgbasic/navbar-menu-bgbasic.html +0 -16
- package/utils/css-animations/buttons/navbar/bgfill/navbar-main-bgfill.html +0 -46
- package/utils/css-animations/buttons/navbar/bgfill/navbar-menu-bgfill.html +0 -39
- package/utils/css-animations/buttons/navbar/color/navbar-announce-color.html +0 -5
- package/utils/css-animations/buttons/navbar/color/navbar-main-color.html +0 -7
- package/utils/css-animations/buttons/navbar/color/navbar-menu-color.html +0 -7
- package/utils/css-animations/buttons/navbar/double-slide/navbar-announce-double-slide.html +0 -40
- package/utils/css-animations/buttons/navbar/double-slide/navbar-main-double-slide.html +0 -77
- package/utils/css-animations/buttons/navbar/scale/navbar-announce-scale.html +0 -6
- package/utils/css-animations/buttons/navbar/scale/navbar-main-scale.html +0 -9
- package/utils/css-animations/buttons/navbar/scale/navbar-menu-scale.html +0 -8
- package/utils/css-animations/buttons/navbar/underline/navbar-announce-underline.html +0 -32
- package/utils/css-animations/buttons/navbar/underline/navbar-main-underline.html +0 -56
- package/utils/css-animations/buttons/text/color/text-footer-color.html +0 -5
- package/utils/css-animations/buttons/text/color/text-main-color.html +0 -5
- package/utils/css-animations/buttons/text/double-slide/text-main-double-slide.html +0 -56
- package/utils/css-animations/buttons/text/scale/text-footer-scale.html +0 -6
- package/utils/css-animations/buttons/text/scale/text-main-scale.html +0 -6
- package/utils/css-animations/buttons/text/underline/text-footer-underline.html +0 -45
- package/utils/css-animations/buttons/text/underline/text-main-underline.html +0 -58
- package/utils/css-animations/cards/card-clickable.html +0 -11
- package/utils/css-animations/defaults.html +0 -69
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# **Custom Select Component**
|
|
2
|
+
|
|
3
|
+
## **Overview**
|
|
4
|
+
|
|
5
|
+
Fully accessible, styled select dropdowns that sync with native `<select>` elements for form submission. Features typeahead search, keyboard navigation, autofill support, and all modern accessibility requirements.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
### **Required Elements**
|
|
10
|
+
|
|
11
|
+
**Select Wrapper** _(main container)_
|
|
12
|
+
|
|
13
|
+
- data-hs-form-select="wrapper"
|
|
14
|
+
|
|
15
|
+
**Native Select** _(hidden select element for form submission)_
|
|
16
|
+
|
|
17
|
+
- Standard `<select>` element with `<option>` children
|
|
18
|
+
- Should have `name` attribute for form submission
|
|
19
|
+
- Will be hidden but remains functional
|
|
20
|
+
|
|
21
|
+
**Toggle Button** _(visual button to open/close dropdown)_
|
|
22
|
+
|
|
23
|
+
- data-hs-form-select="button"
|
|
24
|
+
- Should contain a `<span>` element for displaying selected text
|
|
25
|
+
- Webflow IX must add/remove `.is-active` class on this button for open/close animation
|
|
26
|
+
- Script automatically adds/removes `.is-filled` class based on whether a value is selected
|
|
27
|
+
|
|
28
|
+
**Custom List** _(dropdown container)_
|
|
29
|
+
|
|
30
|
+
- data-hs-form-select="list"
|
|
31
|
+
- First child is used as template for generating options
|
|
32
|
+
- Webflow IX must show/hide this when button is clicked
|
|
33
|
+
|
|
34
|
+
**Template Element** _(first child of select-list)_
|
|
35
|
+
|
|
36
|
+
- Should contain a `<span>` element for option text
|
|
37
|
+
- Will be cloned for each `<option>` in the native select
|
|
38
|
+
- Original template is removed after cloning
|
|
39
|
+
|
|
40
|
+
**Label** _(optional but recommended)_
|
|
41
|
+
|
|
42
|
+
- Standard `<label>` element
|
|
43
|
+
- Can be inside wrapper or reference select by `for` attribute
|
|
44
|
+
|
|
45
|
+
**Typical element layout:**
|
|
46
|
+
|
|
47
|
+
1. Select Wrapper (data-hs-form-select="wrapper")
|
|
48
|
+
1. Label (optional)
|
|
49
|
+
1. Text: "Choose an option"
|
|
50
|
+
2. Native Select (`<select>`)
|
|
51
|
+
1. Option 1 (`<option value="value1">`)
|
|
52
|
+
1. Text: "Option 1"
|
|
53
|
+
2. Option 2 (`<option value="value2">`)
|
|
54
|
+
1. Text: "Option 2"
|
|
55
|
+
3. Toggle Button (data-hs-form-select="button")
|
|
56
|
+
1. Button Text (`<span>`)
|
|
57
|
+
1. Text: "Choose an option"
|
|
58
|
+
4. Custom List (data-hs-form-select="list")
|
|
59
|
+
1. Template Element
|
|
60
|
+
1. Text Span (`<span>`)
|
|
61
|
+
1. Text: "Placeholder"
|
|
62
|
+
|
|
63
|
+
### **What It Does**
|
|
64
|
+
|
|
65
|
+
1. **Unwraps Webflow slots** - Removes any `<div>` wrappers inside `<select>` elements
|
|
66
|
+
2. **Clones template** - Uses first child of select-list as template
|
|
67
|
+
3. **Generates options** - Creates custom option elements from native `<option>` elements
|
|
68
|
+
4. **Syncs state** - Keeps custom UI and native select in sync
|
|
69
|
+
5. **ARIA management** - Automatically updates accessibility attributes
|
|
70
|
+
6. **Keyboard navigation** - Full arrow key, Home/End, Tab, Enter, Space, Escape support
|
|
71
|
+
7. **Typeahead search** - Type to quickly navigate to options (native select behavior)
|
|
72
|
+
8. **Focus management** - Handles focus return, tabbing out, and keyboard navigation
|
|
73
|
+
9. **Value state tracking** - Adds/removes `.is-filled` class on button based on whether an actual value is selected
|
|
74
|
+
10. **Disabled state sync** - Automatically disables button when native select is disabled
|
|
75
|
+
11. **Form reset support** - Updates custom UI when form is reset via `<button type="reset">`
|
|
76
|
+
12. **Autofill support** - Syncs with browser autofill and password managers
|
|
77
|
+
|
|
78
|
+
### **When It Runs**
|
|
79
|
+
|
|
80
|
+
- Runs once on page load (or DOMContentLoaded)
|
|
81
|
+
- Available for manual re-initialization via `window.initCustomSelects()`
|
|
82
|
+
- Runs again on Barba.js page transitions (via `reinitialize()`)
|
|
83
|
+
|
|
84
|
+
### **Interaction Requirements (IX3)**
|
|
85
|
+
|
|
86
|
+
**CRITICAL:** Webflow interactions MUST add/remove `.is-active` class on the toggle button.
|
|
87
|
+
|
|
88
|
+
**Triggers:**
|
|
89
|
+
|
|
90
|
+
1. **Click trigger** on button element (data-hs-form-select="button")
|
|
91
|
+
1. `Each click: Toggle play/reverse`
|
|
92
|
+
|
|
93
|
+
**Timeline:**
|
|
94
|
+
|
|
95
|
+
1. 0s: Toggle `.is-active` class on the button element
|
|
96
|
+
2. .06s: Rest of animation (fade in, slide, etc.)
|
|
97
|
+
|
|
98
|
+
**Class Behavior:**
|
|
99
|
+
|
|
100
|
+
- `.is-active` - Controlled by Webflow IX for dropdown open/close animation state
|
|
101
|
+
- `.is-filled` - Automatically controlled by script to indicate if a value is selected (use for placeholder-like styling)
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## **Accessibility**
|
|
106
|
+
|
|
107
|
+
### **Automatic ARIA Setup**
|
|
108
|
+
|
|
109
|
+
For each select, the system automatically:
|
|
110
|
+
|
|
111
|
+
1. **Button (combobox)**
|
|
112
|
+
- `role="combobox"`
|
|
113
|
+
- `aria-haspopup="listbox"`
|
|
114
|
+
- `aria-expanded="true|false"` (synced with `.is-active` class)
|
|
115
|
+
- `aria-controls="[listbox-id]"`
|
|
116
|
+
- `aria-labelledby="[label-id]"` (if label exists)
|
|
117
|
+
- `aria-activedescendant="[option-id]"` (when navigating with arrows)
|
|
118
|
+
|
|
119
|
+
2. **Select List**
|
|
120
|
+
- `role="listbox"`
|
|
121
|
+
- `tabindex="-1"` (not directly tabbable)
|
|
122
|
+
|
|
123
|
+
3. **Options**
|
|
124
|
+
- `role="option"`
|
|
125
|
+
- `aria-selected="true|false"`
|
|
126
|
+
- `tabindex="0"` when dropdown open, `tabindex="-1"` when closed
|
|
127
|
+
- Unique `id` for aria-activedescendant
|
|
128
|
+
|
|
129
|
+
4. **Label**
|
|
130
|
+
- Connected to native select with `for` attribute
|
|
131
|
+
- Linked to button with `aria-labelledby`
|
|
132
|
+
|
|
133
|
+
### **Focus Management**
|
|
134
|
+
|
|
135
|
+
1. **Opening dropdown** - All options become tabbable
|
|
136
|
+
2. **Closing dropdown** - Focus returns to button if inside list
|
|
137
|
+
3. **Tabbing out** - Automatically closes dropdown
|
|
138
|
+
4. **Arrow navigation** - Focuses options with visual `.focused` class
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## **Usage Examples**
|
|
143
|
+
|
|
144
|
+
### **Basic Select**
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<div data-hs-form-select="wrapper">
|
|
148
|
+
<label for="fruit-select">Choose a fruit</label>
|
|
149
|
+
|
|
150
|
+
<select name="fruit" id="fruit-select">
|
|
151
|
+
<option value="">Choose an option</option>
|
|
152
|
+
<option value="apple">Apple</option>
|
|
153
|
+
<option value="banana">Banana</option>
|
|
154
|
+
<option value="orange">Orange</option>
|
|
155
|
+
</select>
|
|
156
|
+
|
|
157
|
+
<button data-hs-form-select="button">
|
|
158
|
+
<span>Choose an option</span>
|
|
159
|
+
</button>
|
|
160
|
+
|
|
161
|
+
<div data-hs-form-select="list">
|
|
162
|
+
<div>
|
|
163
|
+
<span>Template</span>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Result:** Creates 4 custom options (including empty "Choose an option"). Native select stays synced for form submission.
|
|
170
|
+
|
|
171
|
+
### **Pre-selected Option**
|
|
172
|
+
|
|
173
|
+
```html
|
|
174
|
+
<select name="size">
|
|
175
|
+
<option value="small">Small</option>
|
|
176
|
+
<option value="medium" selected>Medium</option>
|
|
177
|
+
<option value="large">Large</option>
|
|
178
|
+
</select>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Result:** Button text automatically shows "Medium" on page load. Corresponding custom option has `aria-selected="true"`.
|
|
182
|
+
|
|
183
|
+
### **Options with Special Characters**
|
|
184
|
+
|
|
185
|
+
```html
|
|
186
|
+
<option value='product"deluxe"'>Deluxe Edition</option>
|
|
187
|
+
<option value="user's choice">Custom Option</option>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Result:** Works correctly - uses safe value comparison instead of selector injection.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## **Keyboard Navigation**
|
|
195
|
+
|
|
196
|
+
### **When Button is Focused**
|
|
197
|
+
|
|
198
|
+
1. **Space** or **Enter** � Open/close dropdown
|
|
199
|
+
2. **ArrowDown** � Open dropdown (or focus first option if already open)
|
|
200
|
+
3. **ArrowUp** � Focus last option (if dropdown is open)
|
|
201
|
+
4. **Home** � Open dropdown and focus first option
|
|
202
|
+
5. **End** � Open dropdown and focus last option
|
|
203
|
+
6. **Escape** � Close dropdown (if open)
|
|
204
|
+
7. **Alphanumeric keys** � Typeahead search (see below)
|
|
205
|
+
|
|
206
|
+
### **When Option is Focused**
|
|
207
|
+
|
|
208
|
+
1. **ArrowDown** � Focus next option
|
|
209
|
+
2. **ArrowUp** � Focus previous option (or close and focus button if on first option)
|
|
210
|
+
3. **Home** � Jump to first option
|
|
211
|
+
4. **End** � Jump to last option
|
|
212
|
+
5. **Enter** or **Space** � Select option and close dropdown
|
|
213
|
+
6. **Escape** � Close dropdown and return focus to button
|
|
214
|
+
7. **Tab** � Navigate through options, tab out of last option closes dropdown
|
|
215
|
+
8. **Alphanumeric keys** � Typeahead search (see below)
|
|
216
|
+
|
|
217
|
+
### **Typeahead Search**
|
|
218
|
+
|
|
219
|
+
The select supports native-like typeahead functionality:
|
|
220
|
+
|
|
221
|
+
1. **Single character** � Jumps to first option starting with that letter
|
|
222
|
+
2. **Repeated character** � Cycles through options starting with that letter
|
|
223
|
+
- Example: Press "B" → "Banana", press "B" again → "Blueberry", press "B" again → "Banana"
|
|
224
|
+
3. **Multi-character** � Builds search string to find matches
|
|
225
|
+
- Example: Type "te" → "Texas", type "tenn" → "Tennessee"
|
|
226
|
+
4. **Auto-reset** � Search string clears after 500ms of no typing
|
|
227
|
+
5. **Works from button or list** � Typeahead works whether focused on button (opens dropdown) or within list
|
|
228
|
+
6. **Auto-scroll** � Focused option automatically scrolls into view in scrollable lists
|
|
229
|
+
7. **No backspace** � Matches native select behavior (wait for timeout to reset if you mistype)
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## **State Synchronization**
|
|
234
|
+
|
|
235
|
+
### **Native Select � Custom UI**
|
|
236
|
+
|
|
237
|
+
When native select value changes (programmatically or via Webflow):
|
|
238
|
+
|
|
239
|
+
1. Finds matching custom option by value
|
|
240
|
+
2. Updates button text
|
|
241
|
+
3. Updates `aria-selected` on all options
|
|
242
|
+
|
|
243
|
+
### **Custom UI � Native Select**
|
|
244
|
+
|
|
245
|
+
When user selects custom option:
|
|
246
|
+
|
|
247
|
+
1. Updates native select's `value`
|
|
248
|
+
2. Dispatches `change` event on native select
|
|
249
|
+
3. Updates button text
|
|
250
|
+
4. Updates `aria-selected`
|
|
251
|
+
5. Closes dropdown
|
|
252
|
+
|
|
253
|
+
**Both stay in sync at all times.**
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## **Key Attributes Summary**
|
|
258
|
+
|
|
259
|
+
| Attribute | Purpose | Required On |
|
|
260
|
+
| ------------------------------- | -------------------------- | ----------------------- |
|
|
261
|
+
| `data-hs-form-select="wrapper"` | Select wrapper | Wrapper div |
|
|
262
|
+
| `data-hs-form-select="button"` | Toggle button for dropdown | Button element |
|
|
263
|
+
| `data-hs-form-select="list"` | Custom options container | List div |
|
|
264
|
+
| `data-hs-form="form-handler"` | Honeypot spam field | Hidden input (optional) |
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## **API**
|
|
269
|
+
|
|
270
|
+
### **Manual Re-initialization**
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
window.initCustomSelects();
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Re-scans page for new selects and initializes them. Useful for dynamically added content.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## **Notes**
|
|
281
|
+
|
|
282
|
+
1. **Native select required** - Must have actual `<select>` element for form submission
|
|
283
|
+
2. **Button must have span** - `<span>` child is required for text updates
|
|
284
|
+
3. **Button attribute required** - Button must have `data-hs-form-select="button"` attribute
|
|
285
|
+
4. **Template is removed** - First child of list is cloned then deleted
|
|
286
|
+
5. **Webflow IX required** - Must toggle `.is-active` class on button for open/close animation
|
|
287
|
+
6. **Auto class management** - Script automatically adds/removes `.is-filled` class based on value state
|
|
288
|
+
7. **Barba.js compatible** - Automatically cleans up on destroy/reinitialize (including timeouts)
|
|
289
|
+
8. **Silent failures** - Missing required elements cause function to return early (no errors)
|
|
290
|
+
9. **Empty values supported** - Options with `value=""` work correctly (removes `.is-filled` class)
|
|
291
|
+
10. **Special characters safe** - Handles quotes and special characters in option values
|
|
292
|
+
11. **Typeahead search** - Matches native select behavior with 500ms timeout
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## **v2.0.0 Improvements**
|
|
297
|
+
|
|
298
|
+
### **JSON Config System**
|
|
299
|
+
|
|
300
|
+
- Added config.js with all attribute definitions
|
|
301
|
+
- Future-proof: Easy to add aliases or change attribute patterns
|
|
302
|
+
- Self-documenting: All supported attributes in one place
|
|
303
|
+
- Config-based selectors: `data-hs-form-select` attribute namespace
|
|
304
|
+
|
|
305
|
+
### **Typeahead Search**
|
|
306
|
+
|
|
307
|
+
- Native select-like typeahead functionality
|
|
308
|
+
- Single letter cycling (press "B" repeatedly to cycle through "Banana", "Blueberry", etc.)
|
|
309
|
+
- Multi-character search (type "tenn" to find "Tennessee")
|
|
310
|
+
- 500ms auto-reset timeout
|
|
311
|
+
- Works from both button and list focus states
|
|
312
|
+
- Auto-scrolls focused option into view
|
|
313
|
+
|
|
314
|
+
### **Value State Tracking**
|
|
315
|
+
|
|
316
|
+
- Automatic `.is-filled` class management on button
|
|
317
|
+
- Adds `.is-filled` when option with value is selected
|
|
318
|
+
- Removes `.is-filled` when empty/default option selected
|
|
319
|
+
- Enables placeholder-like CSS styling based on value state
|
|
320
|
+
|
|
321
|
+
### **Enhanced Keyboard Navigation**
|
|
322
|
+
|
|
323
|
+
- **Home/End keys** - Jump to first/last option (matches native select)
|
|
324
|
+
- Works from both button and list focus states
|
|
325
|
+
- Auto-opens dropdown if closed
|
|
326
|
+
|
|
327
|
+
### **Disabled State Synchronization**
|
|
328
|
+
|
|
329
|
+
- Automatically syncs button disabled state with native select
|
|
330
|
+
- Observes `disabled` attribute changes on native select
|
|
331
|
+
- Sets `aria-disabled` for accessibility
|
|
332
|
+
- Prevents interaction when disabled
|
|
333
|
+
|
|
334
|
+
### **Form Integration**
|
|
335
|
+
|
|
336
|
+
- **Form reset support** - Listens for form `reset` event, syncs custom UI to default values
|
|
337
|
+
- **Autofill support** - Listens for `input` events to catch browser autofill and password managers
|
|
338
|
+
- **Autocomplete attribute** - Use standard `autocomplete` attribute on native select for proper autofill
|
|
339
|
+
|
|
340
|
+
### **Barba.js / SPA Compatibility**
|
|
341
|
+
|
|
342
|
+
The form system is fully compatible with Barba.js and other SPA frameworks:
|
|
343
|
+
|
|
344
|
+
- Proper cleanup on destroy (removes all event listeners, observers, and timeouts)
|
|
345
|
+
- Fresh initialization on reinitialize
|
|
346
|
+
- Syncs custom select state with native select on new pages
|
|
347
|
+
- Works like fresh page load on new DOM
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## **Common Issues**
|
|
352
|
+
|
|
353
|
+
**Dropdown not opening:**
|
|
354
|
+
|
|
355
|
+
1. Verify Webflow IX adds `.is-active` class to button (not wrapper or list)
|
|
356
|
+
2. Check that button has `data-hs-form-select="button"` attribute
|
|
357
|
+
3. Ensure list exists with `data-hs-form-select="list"`
|
|
358
|
+
|
|
359
|
+
**Button text not updating:**
|
|
360
|
+
|
|
361
|
+
1. Verify button has a `<span>` child element
|
|
362
|
+
2. Check that template element has a `<span>` child
|
|
363
|
+
3. Ensure option values match between native and custom
|
|
364
|
+
|
|
365
|
+
**Options not clickable:**
|
|
366
|
+
|
|
367
|
+
1. Check that template element exists as first child of select-list
|
|
368
|
+
2. Verify template has `<span>` for text
|
|
369
|
+
3. Ensure options are being generated (inspect DOM)
|
|
370
|
+
|
|
371
|
+
**Can't tab to options:**
|
|
372
|
+
|
|
373
|
+
1. Verify dropdown is open (`.is-active` class on button)
|
|
374
|
+
2. Check Webflow IX animation shows the select-list
|
|
375
|
+
3. Ensure `display: none` is removed when open
|
|
376
|
+
|
|
377
|
+
**Form not submitting selected value:**
|
|
378
|
+
|
|
379
|
+
1. Native `<select>` must have `name` attribute
|
|
380
|
+
2. Check that native select's value is updating (inspect DOM or use console)
|
|
381
|
+
3. Verify native select is inside `<form>` element
|
|
382
|
+
|
|
383
|
+
**Dropdown doesn't close when tabbing out:**
|
|
384
|
+
|
|
385
|
+
1. Ensure wrapper element properly contains button and list
|
|
386
|
+
2. Check that `data-hs-form-select="wrapper"` is on wrapper
|
|
387
|
+
3. Verify Webflow IX removes `.is-active` when clicking button again
|
|
388
|
+
|
|
389
|
+
**Spam prevention not working:**
|
|
390
|
+
|
|
391
|
+
1. Verify honeypot field has `data-hs-form="form-handler"`
|
|
392
|
+
2. Ensure field is hidden with CSS (not removed from DOM)
|
|
393
|
+
3. Check that field is inside the `<form>` element
|