diff --git a/README.md b/README.md index 222fe13f6..6b341b70c 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ harder to contribute to. - [Control Props](#control-props) - [Child Callback Function](#child-callback-function) - [Examples](#examples) +- [FAQ](#faq) - [Inspiration](#inspiration) - [Other Solutions](#other-solutions) - [Contributors](#contributors) @@ -287,6 +288,14 @@ The currently selected item. This is called with an object. Read more about the properties of this object in the section "Child Callback Function" +### id + +> `string` | defaults to a generated ID + +You should not normally need to set this prop. It's only useful if you're +server rendering items (which each have an `id` prop generated based on the +`downshift` `id`). For more information see the `FAQ` below. + ## Control Props downshift manages its own state internally and calls your `onChange` and @@ -517,6 +526,36 @@ You'll find other examples in the `stories/examples` folder of the repo. And you'll find [a live version of those examples here](https://downshift.netlify.com) +## FAQ + +
+ +How do I avoid the checksum error when server rendering (SSR)? + +The checksum error you're seeing is most likely due to the automatically +generated `id` and/or `htmlFor` prop you get from `getInputProps` and +`getLabelProps` (respectively). It could also be from the automatically +generated `id` prop you get from `getItemProps` (though this is not likely as +you're probably not rendering any items when rendering a downshift component +on the server). + +To avoid these problems, simply provide your own `id` prop in `getInputProps` +and `getLabelProps`. Also, you can use the `id` prop on the component +`Downshift`. For example: + +```javascript + + {({getInputProps, getLabelProps}) => ( + + + )} + +``` + +
+ ## Inspiration diff --git a/src/__tests__/downshift.misc.js b/src/__tests__/downshift.misc.js index a7adfeab0..736cccbd8 100644 --- a/src/__tests__/downshift.misc.js +++ b/src/__tests__/downshift.misc.js @@ -96,6 +96,12 @@ test('openAndHighlightDefaultIndex can take no arguments at all', () => { ) }) +test('can specify a custom ID which is used in item IDs (good for SSR)', () => { + const id = 'my-custom-id' + const {getItemProps} = setup({id}) + expect(getItemProps({item: 'blah'}).id).toContain(id) +}) + function setup({children = () =>
, ...props} = {}) { let renderArg const childSpy = jest.fn(controllerArg => { diff --git a/src/downshift.js b/src/downshift.js index 2ee341460..b573f6424 100644 --- a/src/downshift.js +++ b/src/downshift.js @@ -33,6 +33,7 @@ class Downshift extends Component { onUserAction: PropTypes.func, onClick: PropTypes.func, itemCount: PropTypes.number, + id: PropTypes.string, // things we keep in state for uncontrolled components // but can accept as props for controlled components /* eslint-disable react/no-unused-prop-types */ @@ -49,6 +50,7 @@ class Downshift extends Component { defaultInputValue: '', defaultIsOpen: false, getA11yStatusMessage, + id: generateId('downshift'), itemToString: i => (i == null ? '' : String(i)), onStateChange: () => {}, onUserAction: () => {}, @@ -93,7 +95,6 @@ class Downshift extends Component { this.state = state } - id = generateId('downshift') root_handleClick = composeEventHandlers( this.props.onClick, this.root_handleClick, @@ -543,7 +544,7 @@ class Downshift extends Component { /////////////////////////////// ITEM getItemId(index) { - return `${this.id}-item-${index}` + return `${this.props.id}-item-${index}` } getItemProps = (