32

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

Orbitum
  • 1,585
  • 5
  • 27
  • 47

7 Answers7

39

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>
tjgragg
  • 693
  • 1
  • 7
  • 8
  • 5
    You genius, lord of all that looks good. Thank you sir. Wrapping it up with a div solved my issue that was having: a super narrow select. – Manuel Aug 22 '19 at 20:45
  • your solution is nice, but when you when open select and resize the window the select menu stays at same position. – Alessander França Jan 24 '20 at 19:40
  • 2
    +1 This is better; the accepted answer is too complicated, which defeats the purpose of using a pre-made component, i just want to import and use with minimal fuss ! – joedotnot May 23 '20 at 18:14
  • this still has a child element that extends to the right and you won't be able to click on elements to the right of the Select – Garr Godfrey Nov 18 '20 at 12:03
  • Hey, I thank you for this solution. It solved a different problem I had which is material-ui dialog hides the react-select menu dropdown. – Juni Brosas Aug 25 '21 at 11:20
20

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%"
 }),
Dave Cole
  • 2,446
  • 2
  • 20
  • 26
18

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

Bai Nguyen
  • 814
  • 7
  • 16
Jona Rodrigues
  • 992
  • 1
  • 11
  • 23
  • Thanks for your answer and working example. It seems working, but I noticed, that there are issue with "SECONDONE" (options2). I have select fields with dynamic options in them (they can be short or long) and I need solution which will work for all cases. Is there any other ways to achieve it or only by tuning letter size/capital-lowercase settings? – Orbitum Nov 16 '17 at 11:37
  • @Orbitum Yes fine-tuning the letter size would improve the UX. Otherwise I edited my answer to include a pure CSS solution. I didn't hard tested it, tell me if it fit your needs better. – Jona Rodrigues Nov 16 '17 at 12:24
  • CSS solution is great too, but again, there are issue with "SECONDONE" (options2). Can you please, check it, so I can accept your answer? – Orbitum Nov 16 '17 at 13:09
  • Sorry I don't see any issue with the "SECONDONE" option: in the fiddle with the CSS solution it just fits fine to me. Can you please make a screenshot of what's bothering you exactly ? – Jona Rodrigues Nov 16 '17 at 15:39
  • Ok this is not the same problem. You asked for selection to fit its content. Now you ask for dropdown to fit the options. let me see if there is a quick solution for this as well. – Jona Rodrigues Nov 16 '17 at 18:06
  • Again, you can always leverage solution 1 just by making the component to have `min-width` equals to the larger option available. – Jona Rodrigues Nov 16 '17 at 18:18
  • 1
    Look at this [fiddle](https://jsfiddle.net/z3a9usj5/5/) to have a glimpse at how your can use both provided solutions to fit your use-case. Now, there are different UI behaviors you may need: do you want the option to fit `Select...` first, then expand to the longest option available only when the drop down is open? or maybe you want it to always be at least the size of the longest option? or maybe you want to have an average width and trim down options being longer than 200px ? Or you may also need only the dropdown to expand independantly... This all you can do by mixing both solutions. – Jona Rodrigues Nov 16 '17 at 18:37
  • Just curios, how and where are you using `react-input-autosize` library in your jsFiddle? – Orbitum Nov 17 '17 at 16:43
  • anyone know how to get this to happen with v2 component and css-in-js? – tcoulson May 22 '18 at 15:02
12

if you're using react-select v3 you can use customStyles object:

const customStyles = {
  container: provided => ({
    ...provided,
    width: 150
  })
};

<Select
    styles={customStyles}
    {...otherProps}
/>
Alessander França
  • 2,697
  • 2
  • 29
  • 52
  • 3
    The questions is to get the select to automatically have the width. So setting a with to a fixed pixel value is no solution! – Flummiboy Sep 08 '20 at 09:36
8

9/2020

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;
    transform: none;
    max-width: none;
  }

In the above example the prop classNamePrefix will equal CUSTOM_PREFIX

classNamePrefix="CUSTOM_PREFIX"

Maged Mohamed
  • 752
  • 8
  • 7
5

09/2021 (react-select v4)

Adding position: static and transform: none will scale the select-container accordingly.

  placeholder: (provided) => ({
    ...provided,
    position: 'static',
    transform: 'none',
  }),
  singleValue: (provided) => ({
    ...provided,
    position: 'static',
    transform: 'none',
  }),
s1gr1d
  • 385
  • 3
  • 11
1

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}
    />
  )
Ryan
  • 22,332
  • 31
  • 176
  • 357