Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Select auto size width

Tags:

When using react-select it is not auto sizing by option value, but using width:100% as you can see in picture:

Select with short values

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

like image 316
Orbitum Avatar asked Oct 04 '17 18:10

Orbitum


People also ask

How do you reduce the size of react select?

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.

How do you style select options in react?

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.


2 Answers

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> 
like image 84
tjgragg Avatar answered Sep 28 '22 00:09

tjgragg


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. :)

like image 21
Jona Rodrigues Avatar answered Sep 27 '22 23:09

Jona Rodrigues