diff --git a/examples/src/app.js b/examples/src/app.js
index ba23d8954b..26c14fa42f 100644
--- a/examples/src/app.js
+++ b/examples/src/app.js
@@ -15,10 +15,12 @@ import NumericSelect from './components/NumericSelect';
import BooleanSelect from './components/BooleanSelect';
import Virtualized from './components/Virtualized';
import States from './components/States';
+import AutoComplete from './components/AutoComplete';
ReactDOM.render(
+
diff --git a/examples/src/components/AutoComplete.js b/examples/src/components/AutoComplete.js
new file mode 100644
index 0000000000..49435b800d
--- /dev/null
+++ b/examples/src/components/AutoComplete.js
@@ -0,0 +1,78 @@
+import React from 'react';
+import createClass from 'create-react-class';
+import PropTypes from 'prop-types';
+import Select from 'react-select';
+
+const STATES = require('../data/states');
+
+var AutoCompleteField = createClass({
+ displayName: 'AutoCompleteField',
+ propTypes: {
+ label: PropTypes.string,
+ searchable: PropTypes.bool,
+ },
+ componentDidMount() {
+ // reveal hidden input for testing
+ document.querySelector('[autocomplete="country"]').classList.remove('Select-hidden');
+ },
+ getDefaultProps () {
+ return {
+ label: 'States:',
+ searchable: true,
+ };
+ },
+ getInitialState () {
+ return {
+ selectValue: '',
+ clearable: true,
+ rtl: false,
+ };
+ },
+ switchCountry (e) {
+ var newCountry = e.target.value;
+ this.setState({
+ country: newCountry,
+ selectValue: null,
+ });
+ },
+ updateValue (newValue) {
+ this.setState({
+ selectValue: newValue,
+ });
+ },
+ toggleCheckbox (e) {
+ let newState = {};
+ newState[e.target.name] = e.target.checked;
+ this.setState(newState);
+ },
+ render () {
+ var options = [
+ { value: 'EN', label: 'England' },
+ { value: 'DE', label: 'Germany' },
+ ];
+ return (
+
+ );
+ }
+});
+
+
+module.exports = AutoCompleteField;
diff --git a/less/control.less b/less/control.less
index 672f063f0f..2839ed363a 100644
--- a/less/control.less
+++ b/less/control.less
@@ -307,6 +307,19 @@
float: left;
}
+// visually hidden fields
+
+.Select-hidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
// Animation
// ------------------------------
diff --git a/scss/control.scss b/scss/control.scss
index 3c54a1480f..f4918620e7 100644
--- a/scss/control.scss
+++ b/scss/control.scss
@@ -285,8 +285,18 @@
position: relative;
}
+// visually hidden fields
-
+.Select-hidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
// Animation
// ------------------------------
diff --git a/src/Select.js b/src/Select.js
index 1e606d21eb..ca3ca3a0db 100644
--- a/src/Select.js
+++ b/src/Select.js
@@ -49,6 +49,7 @@ class Select extends React.Component {
'handleMouseDownOnArrow',
'handleMouseDownOnMenu',
'handleRequired',
+ 'handleSelect',
'handleTouchOutside',
'handleTouchMove',
'handleTouchStart',
@@ -59,10 +60,12 @@ class Select extends React.Component {
'onOptionRef',
'removeValue',
'selectValue',
+ 'handleHiddenInputChange',
].forEach((fn) => this[fn] = this[fn].bind(this));
this.state = {
inputValue: '',
+ isAutoFilled: false,
isFocused: false,
isOpen: false,
isPseudoFocused: false,
@@ -345,7 +348,6 @@ class Select extends React.Component {
if (this.state.inputValue !== event.target.value) {
newInputValue = this.handleInputValueChange(newInputValue);
}
-
this.setState({
isOpen: true,
isPseudoFocused: false,
@@ -364,9 +366,24 @@ class Select extends React.Component {
return newValue;
}
+ handleHiddenInputChange (e) {
+ this.selectValue({ value: e.target.value });
+ // basically a change event on the hidden field means the autoComplete function of the browser was used
+ this.setState({
+ isAutoFilled: true,
+ });
+ }
+
+
handleKeyDown (event) {
if (this.props.disabled) return;
+ if (event.key !== 'Unidentified') {
+ this.setState({
+ isAutoFilled: false,
+ });
+ }
+
if (typeof this.props.onInputKeyDown === 'function') {
this.props.onInputKeyDown(event);
if (event.defaultPrevented) {
@@ -587,6 +604,13 @@ class Select extends React.Component {
this.focus();
}
+ handleSelect (value) {
+ this.setState({
+ isAutoFilled: false,
+ });
+ this.selectValue(value);
+ }
+
clearValue (event) {
// if the event was triggered by a mousedown and not the primary
// button, ignore it.
@@ -598,6 +622,7 @@ class Select extends React.Component {
this.setValue(this.getResetValue());
this.setState({
isOpen: false,
+ isAutoFilled: false,
inputValue: this.handleInputValueChange(''),
}, this.focus);
}
@@ -919,7 +944,7 @@ class Select extends React.Component {
instancePrefix: this._instancePrefix,
labelKey: this.props.labelKey,
onFocus: this.focusOption,
- onSelect: this.selectValue,
+ onSelect: this.handleSelect,
optionClassName: this.props.optionClassName,
optionComponent: this.props.optionComponent,
optionRenderer: this.props.optionRenderer || this.getOptionLabel,
@@ -947,8 +972,10 @@ class Select extends React.Component {
let value = valueArray.map(i => stringifyValue(i[this.props.valueKey])).join(this.props.delimiter);
return (
this.value = ref}
+ autoComplete={this.props.autoComplete}
name={this.props.name}
value={value}
disabled={this.props.disabled} />
@@ -956,8 +983,10 @@ class Select extends React.Component {
}
return valueArray.map((item, index) => (
@@ -1024,6 +1053,7 @@ class Select extends React.Component {
let className = classNames('Select', this.props.className, {
'Select--multi': this.props.multi,
'Select--single': !this.props.multi,
+ 'is-autofilled': this.state.isAutoFilled,
'is-clearable': this.props.clearable,
'is-disabled': this.props.disabled,
'is-focused': this.state.isFocused,
@@ -1084,6 +1114,7 @@ Select.propTypes = {
'aria-labelledby': PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
arrowRenderer: PropTypes.func, // Create drop-down caret element
autoBlur: PropTypes.bool, // automatically blur the component when an option is selected
+ autoComplete: PropTypes.string, // support for form auto completion
autoFocus: PropTypes.bool, // autofocus the component on mount
autofocus: PropTypes.bool, // deprecated; use autoFocus instead
autosize: PropTypes.bool, // whether to enable autosizing or not