feat: add label/value object support for Select options, streamlines normalization
Enables human-readable labels for Select option values, particularly useful when values are hex codes or other technical representations.
Changes
Core logic (select-plugin.ts):
- Detect arrays of
{value, label}objects by checking first element - Extract values and labels separately; fallback to value as label when label is missing
- Fixed array mutation bug where options array was incorrectly modified
- Updated comment to document support for array of
{value, label}objects
Type definitions:
- Added
SelectOption<T>type toselect-types.tsandpublic.ts - Extended
SelectSettingsto acceptSelectOption<U>[]
Examples (Select.stories.tsx):
- Added
ValueLabelObjectsstory demonstrating hex colors with friendly names
Usage
// Before: labels and values were coupled
useControls({
icon: { options: { none: '', IconA, IconB } } // Keys as labels
})
// After: labels and values are independent
useControls({
color: {
options: [
{ value: '#f00', label: 'red' },
{ value: '#0f0', label: 'green' },
{ value: '#00f', label: 'blue' }
]
}
})
Backward compatible with existing array and object formats.
Demo
Labels display in the dropdown while hex color values are returned.
- Fixes pmndrs/leva#551
Original prompt
This section details on the original issue you should resolve
<issue_title>Feature request: Allow label for
optionsbindings?</issue_title> <issue_description>Rather than always have to see the actual values for a multi-value selection, it'd be great if one could specify per-value labels. Maybe along the lines of this:const colorPicker = useControls({ options: [ { value: '#f00', label: 'red' }, { value: '#0f0', label: 'green' }, { value: '#00f', label: 'blue' } ], value: '#f00' });In my current use case I actually want the values to be JavaScript function objects, and I want to make human-readable labels for them.</issue_description>
<agent_instructions>User wants to be able to pass options as a value/label object.</agent_instructions>
Comments on the Issue (you are @copilot in this section)
@gsimone Want to make a PR @danfuzz ?
- Fixes pmndrs/leva#551
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.
Summary by CodeRabbit
- New Features
- Select control now supports label/value object options ({ value, label }) alongside previous formats; missing or mismatched values default to the first option.
- Types
- Runtime-backed typings for Select options updated for more accurate type inference with object-based options.
- Tests
- Added comprehensive tests covering option formats, edge cases, validation and warnings.
- Stories
- Updated Select stories to demonstrate new option formats, component rendering and interactive behavior.
🦋 Changeset detected
Latest commit: 5011336473dc64f45d29c379c8c20e63908b46c7
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 1 package
| Name | Type |
|---|---|
| leva | Patch |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
The latest updates on your projects. Learn more about Vercel for GitHub.
| Project | Deployment | Preview | Comments | Updated (UTC) |
|---|---|---|---|---|
| leva | Preview | Comment | Nov 9, 2025 0:17am |
This pull request is automatically built and testable in CodeSandbox.
To see build info of the built libraries, click here or the icon next to each commit SHA.
Latest deployment of this branch, based on commit 5011336473dc64f45d29c379c8c20e63908b46c7:
| Sandbox | Source |
|---|---|
| leva-minimal | Configuration |
| leva-busy | Configuration |
| leva-scroll | Configuration |
| leva-advanced-panels | Configuration |
| leva-ui | Configuration |
| leva-theme | Configuration |
| leva-transient | Configuration |
| leva-plugin-plot | Configuration |
| leva-plugin-bezier | Configuration |
| leva-plugin-spring | Configuration |
| leva-plugin-dates | Configuration |
| leva-custom-plugin | Configuration |
@copilot Fix the comments and add a story for the new api
@copilot Fix the comments and add a story for the new api
Fixed the comment in select-plugin.ts to document array of {value, label} objects format, and the ValueLabelObjects story demonstrates the new API in commit 5579ffe.
[!NOTE]
Other AI code review bot(s) detected
CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.
Walkthrough
Adds a label/value object API for Select options: introduces zod-driven schemas and runtime types, updates normalize/sanitize/schema/format logic, expands tests and stories to cover { value, label } option objects alongside primitives and record formats, and adds zod as a dependency and a changeset.
Changes
| Cohort / File(s) | Change Summary |
|---|---|
Changeset & Dependency .changeset/fair-donkeys-cheer.md, packages/leva/package.json |
Adds a changeset declaring a patch release and adds zod (^4.1.12) to package dependencies. |
Select plugin implementation packages/leva/src/plugins/Select/select-plugin.ts |
Replaces v8n validation with zod schemas (primitives, key->label records, value/label objects, unions); rewrites normalize() to detect formats and build gathered keys/values; updates sanitize() and schema() to use zod; adds warnings and explicit handling for missing/invalid values; exports selectOptionsSchema, valueLabelObjectSchema, and related types. |
Select plugin tests packages/leva/src/plugins/Select/select-plugin.test.ts |
Adds comprehensive tests for normalize, schema, sanitize, and format, covering primitives, value/label objects, records, mixed/invalid inputs, edge cases, and warnings. |
Select type shapes packages/leva/src/plugins/Select/select-types.ts |
Replaces generic SelectSettings<U> with concrete SelectSettings referencing SelectOptionsType; removes the extra generic on SelectInput; aligns internal types to the new SelectOptionsType. |
Public types & exports packages/leva/src/types/public.ts, packages/leva/src/types/public.test.ts |
Adds runtime-backed types (SelectOption, SelectOptionsType, ValueLabelObjectType) and updates SelectInput, SelectWithValueInput, and SelectWithoutValueInput to support value/label objects; adjusts type tests to reflect narrowed inference for object-labeled options. |
Stories — Select examples packages/leva/stories/inputs/Select.stories.tsx |
Converts to typed Storybook pattern (Meta/StoryObj), replaces templates with Story objects (render/play), adds ValueLabelObjects story and component-as-option examples, and updates story exports and typings. |
Stories — Advanced example packages/leva/stories/advanced/Busy.stories.tsx |
Adjusts an example's select options from a nested structure to a flat set of strings. |
Sequence Diagram(s)
sequenceDiagram
participant Dev as Developer / Consumer
participant Plugin as Select Plugin
participant Zod as Zod Schemas
Dev->>Plugin: normalize(options, value)
Plugin->>Zod: try parse as array of {value,label}
alt matched value/label array
Zod-->>Plugin: matched
Plugin->>Plugin: extract gatheredKeys & gatheredValues
else not matched
Plugin->>Zod: try parse as array of primitives
alt matched primitives
Zod-->>Plugin: matched
Plugin->>Plugin: use primitives as keys/values
else not matched
Plugin->>Zod: try parse as record key->value
alt matched record
Zod-->>Plugin: matched
Plugin->>Plugin: extract keys & values from record
else no match
Plugin-->>Dev: warn("invalid options format") and return empty settings
end
end
end
Plugin->>Plugin: check provided value in gatheredValues
alt value found
Plugin-->>Dev: return { value, settings }
else not found
Plugin-->>Dev: warn("value not in options") and return { value: undefined, settings }
end
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~50 minutes
- Focus areas:
packages/leva/src/plugins/Select/select-plugin.ts: zod schema correctness, normalization control flow, warning semantics, and exported types.- Type impacts in
select-types.tsandtypes/public.ts: ensure backward compatibility and type inference for all option formats. - Tests: ensure new tests accurately reflect intended behavior and edge cases.
- Stories: verify Storybook render/play logic and component-as-option examples render as expected.
"A rabbit hopped through lines of code,
nibbling schema crumbs along the road.
With zod I plant each label, value, seed,
options now speak cleanly—planted deed by deed.
Carrot cheers for tests and stories sown!"
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title clearly describes the main change: adding label/value object support for Select options and streamlining normalization logic. |
| Linked Issues check | ✅ Passed | The PR fully implements the requested feature from #551 with support for { value, label } object format, handles all required formats (primitives, objects, value/label arrays), maintains backward compatibility, and adds comprehensive tests and documentation. |
| Out of Scope Changes check | ✅ Passed | All changes are directly related to implementing the label/value object API. Updates include schema validation, type definitions, tests, stories, and dependencies—all necessary for the feature scope. |
✨ Finishing touches
- [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
- [ ] Commit unit tests in branch
copilot/add-labels-for-options-bindings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
@coderabbitai review
✅ Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
@coderabbitai review
✅ Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
@coderabbitai review
✅ Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
@coderabbitai generate docstrings
✅ Actions performed
Initiated docstring generation; will generate only if new commits exist.
[!WARNING] Docstrings generation - IN PROGRESS
Generating docstrings for this pull request
@coderabbitai review
✅ Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
✅ Actions performed
Initiated docstring generation; will generate only if new commits exist.