When using react-select
it is not auto sizing by option value, but using width:100%
as you can see in picture:
Options are short:<
SOLUTION 1
You can leverage React's inline styles
by updating the components' width
based on the length of the selected option.
Let me explain further: Say the selected value is HelloWorld
. This string is of length 10
. We could guess that each character accounts for say 8px
each on average (total guess I have no clue at all). Thus, the width of this word is around 8*10=80px
, right ? Also, there are some controls after the word (the carret and the cross) and we need some minimum padding: together they may be of 100px
width. Then here you have it: your div's width should be ( 8px * 10 letters ) + 100px = 180px
.
More precisely, the correct formula is something like:
(average_letter_size * selected_value.length) + other_elements_sizes
When selected_value
changes, so does its length
, and therefore the width of the div gets updated with the new total.
Example: if the selected value is now Lorem Ipsum dolor sit amet
, the length is now 26
. By applying the formula we get a larger width of : (8px * 26 letters) + 100px = 308px
.
For this to work in react, here is a snippet:
<Select
style={{width: `${(8*this.state.selectedOption2.length) + 100}px`}}
className="select-custom-class"
name="form-field-name"
value={this.state.selectedOption2}
options={options2}
onChange={(value) => { this.setState({ selectedOption2: value.value }); }}
/>
As you can see I added :
style={{width: `${(8*this.state.selectedOption2.length) + 100}px`}}
to your component. Whenever the state gets updated, everything is propagated including the width of the component.
See a working example in this fiddle.
Eventually, you want to fine-tune the rules and averages to your needs. I also suggest you apply a letter size depending on the number of capital and lowercase letters in the selected value.
SOLUTION 2 (edit)
I came up with a pure CSS solution if you want. It should be better tested against your design, but this should work:
// .Select-value comes with an absolute position to stack it below .Select-input
// we need to scratch that in order for us to be able to let the div grow depending on its content size
.Select-placeholder, .Select--single > .Select-control .Select-value {
position: relative;
padding-left: 0;
}
// All these 3 classes come with ugly "table" display...
.Select-control, .Select-clear-zone, .Select-arrow-zone {
display: inherit;
}
// here is the trick: we display the wrapper as flex in order to make it fit in height
// we flip positions of .Select-value and .Select-input using row-reverse in order to have a nice input to the left and no to the right
.select-custom-class .Select-multi-value-wrapper {
display: flex;
flex-direction: row-reverse;
}
// we put our controls back to a better center position
.Select-clear-zone {
position: absolute;
top: 8px;
right: 20px;
}
.Select-arrow-zone {
position: absolute;
top: 8px;
right: 0px;
}
See a working fiddle (I changed some of the examples for better illustration)
Tell me what you think. :)
Inline styles did not work for me. I just wrapped the Select component in a div and gave the div the width I wanted.
<div style={{width: '300px'}}>
<Select
menuPlacement="auto"
menuPosition="fixed"
etc, etc..
/>
</div>
Update: for people who are using React-Select for a "tags autocomplete" feature but are having trouble where it sets a style width that is too narrow based on the previous tag you searched, this is what works for me:
Set a style of:
.myCustomPrefix__value-container > div {
width: auto !important;
}
Set classNamePrefix="myCustomPrefix"
in the component (docs).
Old answer:
See the official docs at https://react-select.com/styles#style-object
I originally thought that setting width
to "auto" for option
worked for me:
const customStyles = {
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
return {
...styles,
fontSize: '12px',
textAlign: 'left',
width: 'auto',
}
},
}
...
return (
//https://react-select.com/props
<AsyncSelect
components={animatedComponents}
isMulti
// isDisabled={isLoading}
// isLoading={isLoading}
onChange={handleChange}
onInputChange={handleInputChange}
cacheOptions
defaultOptions
defaultMenuIsOpen={false}
closeMenuOnSelect={closeMenuOnSelect}
placeholder={placeholder}
loadOptions={promiseOptions}
value={selectedOptions}
styles={customStyles}
formatOptionLabel={formatOptionLabel}
/>
)
if you're using react-select v3 you can use customStyles object:
const customStyles = {
container: provided => ({
...provided,
width: 150
})
};
<Select
styles={customStyles}
{...otherProps}
/>
Hey guys :) the solution is so simple than that workarounds !
the problem in these classes __placeholder
, __single-value
just add this css to both of them and you will get auto sized react-select
.CUSTOM_PREFIX__single-value,
.CUSTOM_PREFIX__placeholder {
position: static;
top: auto;
left: auto;
transform: none;
max-width: none;
}