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>