I'm new to Downshift and really impressed with what I've seen so far! I just want to provide some feedback regarding one aspect I'm struggling with - implementing a simple "dropdown select" component (similar to HTML "select" element) where the items are not just strings, but instead "key/value" pairs.
I'm finding that most examples use a string array for their items and also they usually start with an empty default value, allowing the user to type into the input and show suggestions in the dropdown menu. I don't want any input at all. Instead, I want a list of item objects that represent key/value pairs (such as "id" and "label" for example), then I want to be able to set the selectedItem using a string prop that specifies the "item id" only.
When I came to Downshift for the first time, what I was hoping to find was a simple example that demonstrates how to implement the following component in Downshift:
const items = [{ id: 'one', label: 'Item 1' }, { id: 'two', label: 'Item 2' }];
<Select selectedItem='two' items={items}/>
The requirements being:
Item 2 is selected by default.items is an array of objects rather than strings.selectedItem prop is a string representing the select item as the "id" attribute in the items array. I've been trying to implement this off and on for a few days now but all my attempts so far feel a bit to hacky for my liking and I think I'm missing something fundamental about how Downshift works. I can鈥檛 seem to figure out the right way to have a selectedItem representing the "id" in the items object, if that makes sense?
Hello @pdrummond, I was struggling with the same issue and I came up with a simple solution.
In my case, I've had a <input type="text" /> where while I'm typing, I open a dropdown with the options. My problem was the same as yours, I have a list of objects that I want to bind the value of the input as e.g the id of the object, but I want to display the name of the object for the user in the text field.
I ended up storing the value that I want in a hidden input, and the "fancy" input I display the user friendly label. Check this out:
// ...Downshift wraps this component
<SelectWrapper {...getRootProps({ refKey: 'innerRef' })}>
{/* In the input hidden I store the actual value */}
<input type="hidden" name={name} value={inputValue} />
{/* This is the input the user's will se and interact with */}
<StyledTextInput
{...getInputProps({ placeholder })}
label={label}
isOpen={isOpen}
onClick={toggleMenu}
error={error}
value={selectedItem && selectedItem.label}
/>
{isOpen ? (
<OptionList style={{ border: '1px solid #ccc' }}>
{Children.map(this.props.children, (el, index) =>
// ... rest of implementation, not relevant
The usage looks like this:
<Select label="Select Industry" name="industries">
<Select.Option label={'Agriculture'} value={'agriculture'}>
Agriculture
</Select.Option>
<Select.Option label={'Art & Design'} value={'art_design'}>
Art & Design
</Select.Option>
</Select>
So in the end, when I am using this component in a form, the value will be stored in the hidden input that I also assigned the name of the input.
Hope this works for you!
I'm also using a hidden input but it really seems to me that it is a code smell. Moreover, while integrating with redux-form and material-ui, I'm facing bugs such as onBlur not working. An example would definitely be appreciated :-)
I usually solve this by doing something like this: https://codesandbox.io/s/xpwovvx5vz
The usage looks like this. The defaultValue or value have to match the value of one of the items in the options array.
<Select
label="Select fruit"
defaultValue="apple"
options={[
{ value: "apple", label: "Apple" },
{ value: "orange", label: "Orange" }
]}
/>
When you need to use this in a form I usually use a native <select /> element and sync the selectedItem to it. I can provide an example of it if anyone is interested.
+1
Closing this due to inactivity. Please open a new issue if needed.
Are the work around's suggested here still the best way to achieve this? Isn't this a pretty common use case to need to present the label to the user and then use the value only when submitting the form?
Most helpful comment
I usually solve this by doing something like this: https://codesandbox.io/s/xpwovvx5vz
The usage looks like this. The
defaultValueorvaluehave to match thevalueof one of the items in theoptionsarray.When you need to use this in a form I usually use a native
<select />element and sync theselectedItemto it. I can provide an example of it if anyone is interested.