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

Don't set the first option as selected in select tag with size attribute #14242

Merged
merged 3 commits into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add comment about why size is assigned on select create. Tests
I added some more clarification for why size must be set on select
element creation:

- In the source code
- In the DOM test fixture
- In a unit test
  • Loading branch information
nhunzaker committed Feb 28, 2019
commit b3acfd97192b1a72d4843143f0bc2a7e3460f0b7
16 changes: 14 additions & 2 deletions fixtures/dom/src/components/fixtures/selects/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,10 @@ class SelectFixture extends React.Component {

<TestCase
title="A select with the size attribute should not set first option as selected"
relatedIssues="14239">
relatedIssues="14239"
introducedIn="16.0.0">
<TestCase.ExpectedResult>
First option should not be set
No options should be selected.
</TestCase.ExpectedResult>

<div className="test-fixture">
Expand All @@ -217,6 +218,17 @@ class SelectFixture extends React.Component {
<option>2</option>
</select>
</div>

<p className="footnote">
<b>Notes:</b> This happens if <code>size</code> is assigned after
options are selected. The select element picks the first item by
default, then it is expanded to show more options when{' '}
<code>size</code> is assigned, preserving the default selection.
</p>
<p className="footnote">
This was introduced in React 16.0.0 when options were added before
select attribute assignment.
</p>
</TestCase>
</FixtureSet>
);
Expand Down
26 changes: 26 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMSelect-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,32 @@ describe('ReactDOMSelect', () => {
expect(node.options[2].selected).toBe(true); // gorilla
});

it('does not select an item when size is initially set to greater than 1', () => {
let stub = (

This comment was marked as resolved.

This comment was marked as resolved.

<select size="2">
<option value="monkey">A monkey!</option>
<option value="giraffe">A giraffe!</option>
<option value="gorilla">A gorilla!</option>
</select>
);
const container = document.createElement('div');
const select = ReactDOM.render(stub, container);

expect(select.options[0].selected).toBe(false);
expect(select.options[1].selected).toBe(false);
expect(select.options[2].selected).toBe(false);

// Note: There is an inconsistency between JSDOM and Chrome where
// Chrome reports an empty string when no value is selected for a
// single-select with a size greater than 0. JSDOM reports the first
// value
//
// This assertion exists only for clarity of JSDOM behavior:
expect(select.value).toBe('monkey'); // "" in Chrome
// Despite this, the selection index is correct:
expect(select.selectedIndex).toBe(-1);
});

it('should remember value when switching to uncontrolled', () => {
let stub = (
<select value={'giraffe'} onChange={noop}>
Expand Down
4 changes: 4 additions & 0 deletions packages/react-dom/src/client/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ export function createElement(
if (props.multiple) {
node.multiple = true;
} else if (props.size) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested in Chrome and noticed that when a select element is marked as multiple, this issue is not present so the else if seems OK.

// Setting a size greater than 1 causes a select to behave like `multiple=true`, where
// it is possible that no option is selected.
//
// This is only necessary when a select in "single selection mode".
node.size = props.size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small thing, but could you add a comment indicating that assigning size early is only necessary when multiple is false?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like, this does essentially the same thing as setting multiple=true before options are appended because they visually become similar:

https://codepen.io/nhunzaker/pen/VgRQEy

}
}
Expand Down