Merged
Conversation
…yling and gathering similar logic from other dropdown components from different libraries as well as epinios use case
johnlcos
requested changes
Mar 19, 2026
src/components/dropdown/dropdown.ts
Outdated
| return html` | ||
| <div class="dropdown-panel" role="listbox" aria-multiselectable=${this.multiselect}> | ||
| <div class="search-wrapper"> | ||
| <input |
Member
There was a problem hiding this comment.
I think we should add a prop that enables the filter input. I can see places where it may not be needed.
| label = ''; | ||
|
|
||
| @property({ type: Boolean }) | ||
| required = false; |
Member
There was a problem hiding this comment.
Right now required doesnt behave as you would expect in a form. If the user tries to submit a form without selecting from the dropdown, we want the submit to be blocked and the user to be notified. I think we can probably handle this similar to the validity methods added to the text input component
- Add boolean prop to opt-in to a search input at the top of the panel (works for both single and multiselect) - Remove inline search from multiselect triggersearch now lives consistently in the panel for all modes when filterable is enabled - Implement via ElementInternals so required dropdowns block form submission and surface a native validation message - Expose , , and as public methods delegating to internals (standard FACE pattern) - Use lifecycle to re-validate when required/value/values change without a user interaction - Add WithFilter and MultiselectWithFilter Storybook stories - Update tests: replace inline-search assertion, add filterable beforeEach to Filtering suite, add Required validation test group
…railhand-ui into feat/TRAIL-4_dropdown_component
…railhand-ui into feat/TRAIL-4_dropdown_component
johnlcos
requested changes
Mar 20, 2026
| this._updateValidity(); | ||
| } | ||
|
|
||
| private _updateValidity() { |
Member
- Defer invalid visual state until user interacts or submit is attempted - Fix required border showing blue on submit — add invalid event listener, outline: none on trigger, and strengthen invalid CSS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Fixes: #
Related Tickets: TRAIL-4 https://jira.atlassian.krum.io/browse/TRAIL-4?atlOrigin=eyJpIjoiNDRlZTg3NjA2ODZkNDBkMjkxNzE2OWVkODJhZGFkMTMiLCJwIjoiaiJ9
Adds a new
trailhand-dropdownweb component supporting single and multiselect modes withbuilt-in search filtering, keyboard navigation, form association, and full dark mode support.
Also integrates the dropdown into the existing dev examples and form modal mockups.
Type of Change
Changes Made
Primary Changes
trailhand-dropdownLit web component with single and multiselect supporttrailhand-tag(info, sm, dismissible)clearOthers: booleanflag onDropdownOptiondesignates an option that deselects all others when selected (e.g. "All Namespaces"), and is itself deselected when any other option is chosen<form>withFormData, includingformResetCallbackandformDisableCallback; multiselect usesFormDatato submit multiple values under the same namesizeprop (small / medium / large),disabled,required,invalid,label,placeholdermin-width: var(--th-dropdown-min-width, 220px)prevents the trigger from collapsing to fit its selected valuecomposedPath()for correct shadow DOM handlingSecondary/Collateral Changes
--th-dropdown-*CSS custom properties tocolors.cssfor both light and dark themes (background, option text, selected/hover states, shadow)--th-input-bgincolors.csswas set to'transparent'(quoted string, invalid CSS); corrected tovar(--th-color-grey-200)so disabled inputs and the disabled dropdown trigger both show a visible grey background in light modebackground: var(--th-input-bg)to the disabled trigger to matchtext-inputdisabled treatmentdev/main.ts(Namespace, Catalog Service, Bind to Application fields replaced with dropdowns)src/index.tsTechnical Notes
Files Modified
New files:
src/components/dropdown/dropdown.tscomponent implementationsrc/components/dropdown/dropdown.stories.tsStorybook stories with formatted code snippetssrc/components/dropdown/dropdown.test.tsVitest unit testsModified files:
src/components/dropdown/index.tsexport wired up (was empty placeholder)src/index.tsaddedexport * from './components/dropdown'src/styles/colors.cssnew--th-dropdown-*variables (light + dark), fixed--th-input-bgdev/main.tsdropdown import, showcase section, modal field updatesImplementation Details
clearOthersdesign: The "All" behavior is a per-option flag rather than a component-level prop. This keeps the component generic the consumer controls which option(s) carry the behavior through their data, with no hardcoded concept of "all" in the component itself. Multiple options can carry the flag if needed.Outside click handling: Uses
e.composedPath().includes(this)instead ofe.targetto correctly detect clicks inside shadow DOM children without requiringstopPropagationon every internal interaction.Dark mode panel background: The dropdown panel uses
var(--th-dropdown-bg)which is defined per-theme incolors.css. Previously the fallback was hardcoded#ffffff, making the panel appear white in dark mode. The fix required adding explicit variables tocolors.cssrather than relying on inheritance, since the panel sits in shadow DOM and doesn't automatically inheritdata-themestyles from the document.Multiselect form values: Uses
internals.setFormValue(FormData)to submit multiple values under the same field name, which is the correct approach per the FACE spec for multi-value fields.Testing
How to Test
npm run devand navigate to the Dropdowns sectiondisabledconfirm trigger shows grey background and cannot be openednpm run test:unitconfirm all dropdown tests passTest Coverage
Browsers Tested
Potential Regressions
--th-input-bgfix incolors.cssnow applies a grey background to disabledtrailhand-text-inputfields in light mode (previously transparent due to the invalid quoted value). This is the intended behavior but worth a visual check on any forms with disabled inputs.Screenshots / Videos
Checklist
clearOthersJSDoc with example)