feat(SelectDropdown): isCreateable support, removes SearchIcon, styling fixes#3371
feat(SelectDropdown): isCreateable support, removes SearchIcon, styling fixes#3371dreamwasp wants to merge 29 commits into
isCreateable support, removes SearchIcon, styling fixes#3371Conversation
|
View your CI Pipeline Execution ↗ for commit e7a0f1a ☁️ Nx Cloud last updated this comment at |
❌ 2 Tests Failed:
View the top 2 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3371 +/- ##
==========================================
- Coverage 90.55% 90.38% -0.17%
==========================================
Files 398 274 -124
Lines 6586 5702 -884
Branches 2105 1898 -207
==========================================
- Hits 5964 5154 -810
+ Misses 613 539 -74
Partials 9 9
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds “creatable” support to the Gamut SelectDropdown (single + multi), updates dropdown indicator icon behavior (removes the search icon), and reorganizes/expands Styleguide documentation and examples to cover controlled/uncontrolled + creatable patterns.
Changes:
- Implement
isCreatablesupport (includingformatCreateLabel,isValidNewOption,onCreateOption, andvalidationMessage) and route rendering throughreact-select/creatable. - Update dropdown visuals/behavior (remove searchable SearchIcon indicator, tweak menu/option styling).
- Expand and reorder Storybook docs/stories (new creatable stories + new docs tables) and add corresponding unit tests.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/SelectDropdown.stories.tsx | Reorders stories and adds new creatable examples (single, multi, validation). |
| packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/SelectDropdown.mdx | Restructures docs and adds creatable + controlled/uncontrolled guidance and tables. |
| packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/creatablePropsTable.tsx | Adds a props table documenting creatable-specific API surface. |
| packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/controlledModeTable.tsx | Adds a table clarifying controlled vs uncontrolled patterns across modes. |
| packages/gamut/src/Form/SelectDropdown/types/styles.ts | Extends option-state typing to support creatable “Add” row metadata. |
| packages/gamut/src/Form/SelectDropdown/types/component-props.ts | Adds new creatable-related props and a TS constraint tying isCreatable to isSearchable. |
| packages/gamut/src/Form/SelectDropdown/styles.ts | Styling updates for menu shadow/no-options text and creatable “Add” row styling. |
| packages/gamut/src/Form/SelectDropdown/SelectDropdown.tsx | Wires new creatable props into the SelectDropdown implementation and forwards new callbacks. |
| packages/gamut/src/Form/SelectDropdown/elements/options.tsx | Avoids rendering selection checkmark on the creatable “Add” row. |
| packages/gamut/src/Form/SelectDropdown/elements/controls.tsx | Removes SearchIcon indicator selection logic; always uses chevron indicator. |
| packages/gamut/src/Form/SelectDropdown/elements/containers.tsx | Switches underlying implementation to CreatableSelect when isCreatable is set. |
| packages/gamut/src/Form/SelectDropdown/elements/constants.ts | Removes SearchIcon and searchable indicator variants. |
| packages/gamut/src/Form/tests/SelectDropdown.test.tsx | Adds/extends tests for creatable behavior and validationMessage. |
| packages/gamut/agent-tools/skills/gamut-select-dropdown/SKILL.md | Adds a SelectDropdown-specific agent skill documenting patterns/pitfalls. |
| packages/gamut/agent-tools/skills/gamut-forms/SKILL.md | Links forms skill to the new SelectDropdown skill for dropdown-specific guidance. |
| if (actionMeta.action === 'create-option') { | ||
| onCreateOption?.(actionMeta.option?.value ?? ''); | ||
| } |
| ```tsx | ||
| <FormGroup htmlFor="country" isSoloField label="Country" error={errors.country}> | ||
| <SelectDropdown | ||
| name="country" |
There was a problem hiding this comment.
this needs to be id. name doesnt match them up. its id on the control matches htmlFor on the label, or you can pass htmlFor on the control and it becomes id downstream (kinda weird imo)
| /** When true, renders CreatableSelect instead of ReactSelect */ | ||
| isCreatable?: boolean; | ||
| /** Customises the "Add" row label */ | ||
| formatCreateLabel?: (inputValue: string) => React.ReactNode; | ||
| /** Controls visibility of the "Add" row */ | ||
| isValidNewOption?: ( | ||
| inputValue: string, | ||
| value: OptionsType<OptionStrict>, | ||
| options: OptionsType<OptionStrict> | ||
| ) => boolean; |
There was a problem hiding this comment.
can this be DRYed up with the props above? seeing the same thing twice
| mode: 'Creatable multi', | ||
| uncontrolled: ( | ||
| <> | ||
| Omit <Code>value</Code>; use <Code>onCreateOption</Code> for option |
| - `FormGroup` `htmlFor` must match control `id` (not `name`). Alternatively, pass `htmlFor` directly on SelectDropdown and it becomes `id` downstream. | ||
| - Pass `name` on SelectDropdown (required for forms). | ||
| - Pass `aria-label` (required for forms); it must match the FormGroupLabel `htmlFor` / `name`. | ||
| - Pass `aria-label` (required for forms); it must match the FormGroupLabel `htmlFor`. |
There was a problem hiding this comment.
is this true? isnt this not needed bc of the form group label?
There was a problem hiding this comment.
yeah this is an overstatement, i'll fix
|
|
||
| - `FormGroup` `htmlFor` must match control `id` (not `name`). Alternatively, pass `htmlFor` directly on SelectDropdown and it becomes `id` downstream. | ||
| - Pass `name` on SelectDropdown (required for forms). | ||
| - Pass `aria-label` (required for forms); it must match the FormGroupLabel `htmlFor`. |
There was a problem hiding this comment.
is this true? i thought it just uses the form group label?
Co-authored-by: Amy Resnik <aresnik@codecademy.com>
|
📬 Published Alpha Packages:
|
|
🚀 Styleguide deploy preview ready! Preview URL: https://6a4d064e6a84e72180ac515a--gamut-preview.netlify.app |
LinKCoding
left a comment
There was a problem hiding this comment.
Just looked over some skills and the new docs
but looks really good :D
|
|
||
| ## Options | ||
|
|
||
| `options` accepts plain strings or option objects. `value` is always a string and references an option's `value`. |
There was a problem hiding this comment.
more accurate to say options accepts an array of plain strings or option objects.
|
|
||
| `options` accepts plain strings or option objects. `value` is always a string and references an option's `value`. | ||
|
|
||
| | Field | Required | Notes | |
There was a problem hiding this comment.
I think some context could help, maybe something like, the table below shows the keys and values of an options object.
Though the "Notes" could be updated, or adding a dedicated column for type of value.
|
|
||
| ## Controlled vs uncontrolled | ||
|
|
||
| SelectDropdown does **not** accept `defaultValue`. |
There was a problem hiding this comment.
| SelectDropdown does **not** accept `defaultValue`. | |
| `SelectDropdown` does **not** accept `defaultValue`. |
|
|
||
| ## When to use SelectDropdown vs Select | ||
|
|
||
| Use `Select` for standard single-select forms with minimal bundle cost. Use `SelectDropdown` when designs specify the styled dropdown menu, search, multi-select tags, creatable options, icons, groups, or abbreviations. SelectDropdown has a larger JavaScript dependency (react-select). |
There was a problem hiding this comment.
| Use `Select` for standard single-select forms with minimal bundle cost. Use `SelectDropdown` when designs specify the styled dropdown menu, search, multi-select tags, creatable options, icons, groups, or abbreviations. SelectDropdown has a larger JavaScript dependency (react-select). | |
| Use `Select` for standard single-select forms with minimal bundle cost. Use `SelectDropdown` when designs specify the styled dropdown menu, search, multi-select tags, creatable options, icons, groups, or abbreviations. `SelectDropdown` has a larger JavaScript dependency (react-select). |
| { | ||
| key: 'mode', | ||
| name: 'Mode', | ||
| size: 'md' as const, |
| }, | ||
| }, | ||
| }, | ||
| render: () => <CreatableMultiUncontrolledStoryRender />, |
There was a problem hiding this comment.
same note here re: exposing the code
| }, | ||
| }, | ||
| }, | ||
| render: () => <CreatableMultiStoryRender />, |
There was a problem hiding this comment.
same note here re: exposing the code
| }; | ||
|
|
||
| export const CreatableWithValidation: Story = { | ||
| render: () => <CreatableWithValidationStoryRender />, |
There was a problem hiding this comment.
same note here re: exposing the code
| <Canvas of={SelectDropdownStories.MultipleSelectControlled} /> | ||
|
|
||
| #### Small size with independent widths | ||
| `onChange` receives option objects (`{ label, value }`), not `event.target.value`. The second argument is react-select action metadata — use `meta.action === 'create-option'` in creatable mode. |
There was a problem hiding this comment.
I think this could be more clear with an example, and I think it pairs really well with the validation example you had with the skills
that or maybe provide rationale for when/why you might to check for this 2nd argument
| Gate which inputs can be created with `isValidNewOption` — return `false` to hide the **Add** row. Use `validationMessage` to replace the default "No options" text with contextual feedback, and mirror the same message in `FormGroup`'s `error` prop so it's surfaced below the field. | ||
|
|
||
| ## Accessibility | ||
| Because react-select clears the input on blur, persist validation state via `onInputChange`: validate on `input-change`, and re-validate from the last typed value on `input-blur` so the `FormGroup` error isn't lost when the input clears. |
There was a problem hiding this comment.
Nit: I think omitting react-select here is ok
Something like: Because the default behavior is to clear the input on blur, use onInputChange to ...




Overview
Adds
isCreatablesupport toSelectDropdownfor single + multi-select, letting users type and add options not already in the list. Also removes theSearchIconfrom searchable dropdowns (replaced with arrow). I also added a SelectDropdown agent skill (referenced in the form skill), made some styling fixes, and rearranged Storybook documentation to have a better flow.PR Checklist
Testing Instructions
PR Links and Envs