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:
getOptions() { return [ { value: 'AND', label: 'AND' }, { value: 'OR', label: 'OR' } ] }
And code which produces it:
<Select options={this.getOptions()} value={value} autosize={true} clearable={false} simpleValue />
Is there any way to make react-select
to show these values with auto sizing, so select box would be the same as option length, and I could, for example, center this select box in <div>
?
Updated 14.11.2017 Full example can be seen in this jsFiddle
Read the react-select docs HERE. React-Select v2 uses emotion CSS-in-JS so the new way to control style over the select components and sub-components is by passing a style object to the styles prop. You can also set a className to style with an external stylesheet.
To style react-select drop down options, we can create an object with the styles we want to apply and set that as the value of the styles prop. We create the colourStyles object with the control method that return an object with the styles. And we have the option method that returns the styles for the options.
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>
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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With