React Select auto size width
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. :)
I borrowed this from aidan-keay on the repo thread, but adding this to the custom styles prop worked for me:
menu: (base) => ({
...base,
width: "max-content",
minWidth: "100%"
}),
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>