Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 16 continues to incorrectly handle disabled <options> as #2803 #11100

Closed
StoneCypher opened this issue Oct 4, 2017 · 5 comments
Closed

Comments

@StoneCypher
Copy link

StoneCypher commented Oct 4, 2017

I would like to report my bug #2803 again please, because it was closed, and @gaearon said "re-open it if it's still a problem."

As I currently understand it, React is incorrectly handling a common case in the construction of <select>s. It is fairly normal to create a <select> where the first element is disabled, but remains pre-selected.

React should render this case, but instead renders the first deselected control.

I attempted to fix this by forcing the selection. The normal approach is to set selected on the relevant <option>, but React disallows this, preferring a novel property defaultValue on the <select> instead, mimicing a first-write version of the <select> property value.

If you attempt to set defaultValue, what you set is ignored (it may be the case that defaultValue is broken on select.)

React's inability to render a disabled <option> as either the default or selected initial has been present since at least sometime mid-version-14, which is when I first found it. I first documented it in 15.3.1 in January 2015, because prior to then it was faster to tell the core devs on IRC. I do not know how far it goes back past mid-r14.

@amackintosh
Copy link

I am encountering this now. Here is a component you can use to test:

import React from 'react'

const TestSelect = ({ placeholder, options }) => (
  <select
    style={{ height: '50px', width: '100px', marginTop: '100px' }}
    name={name}>

    <option
      value={0}
      disabled>
      {placeholder}
    </option>

    {options.map((opt, i) =>
      <option
        key={i}
        value={opt}
        style={{ color: '#000' }}>
        {opt}
      </option>
    )}
  </select>
)

export default () => {
  return (
    <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', flex: 1, height: '500px' }}>
      <h2>YOLO</h2>
      <div>
        <TestSelect
          placeholder="Select an option"
          options={['one', 'two', 'buckle de la shoe']}
        />
      </div>
    </div>
  )
}

I believe a decent solution is to leave the default option enabled (not disabled), and then check if the value of that field is 0 as part of your form validation.

I do this in React Native. I am noticing now, the value is a string "0" in React, but I am pretty sure it is a number in React Native because I recall my validation is just checking if (!field.name) errors.name = 'You should probably fill that out.'

This way, you can just maintain the value of unselectable options as value={0} and the validator will never let them through because falsy value.

With that said, it is currently annoying me because I cannot have the first option in my <select> element being the default value when the form loads.

  1. If I set the option to disabled={true}, it displays the first option in the list as the default value. In my above example code, the default value is "one" not "Select an option" if disabled={true}
  2. If I set the option to disabled={false}, it displays the first option in the list as "Select an option" (as desired), but allows the user to select it and it becomes a truthy value that must be dealt with.

This is an easy work-around for me anyway. I will just do in my redux-form validate function:

if (!field.name || field.name === '0') errors.name = 'You must select an option.'

@jquense
Copy link
Contributor

jquense commented Nov 16, 2017

@amackintosh your example seems to work fine if you use defaultValue: https://jsfiddle.net/Luktwrdm/39/ It's not selected by default because the html spec says that the first non-disabled item should be the "default" item when nothing is marked as selected. see #10456 for more info

Gonna close this out. Disabled options can be be selected via the normal React means, either with defaultValue or controlling the value. The original error stems from a miscommunication about what defaultValue is (it's not the index), there is more details in #11099

@jquense jquense closed this as completed Nov 16, 2017
@denisftw
Copy link

@jquense The problem with this Fiddle is that it actually uses selected and produces the following in the console:

Warning: Use the defaultValue or value props on instead of setting selected on "option".

@robjtede
Copy link

Just come across this. Long time web dev, recent React user. Why isn't this possible without being complained at in the console?

@StoneCypher
Copy link
Author

i submitted a patch that did exactly that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants