Repository: laboratoriobridge/bold
Pull request #487 (2019-10-14 16:43:52)

Using popper to position Select


Patch:
diff --git a/src/components/Select/SelectMenu/SelectMenu.tsx b/src/components/Select/SelectMenu/SelectMenu.tsx
index 09ff566ff..8a9105b8d 100644
--- a/src/components/Select/SelectMenu/SelectMenu.tsx
+++ b/src/components/Select/SelectMenu/SelectMenu.tsx
@@ -27,7 +27,6 @@ export const createStyles = (theme: Theme) => ({
     maxHeight: '20rem',
     overflowY: 'auto',
     overflowX: 'hidden',
-    position: 'absolute',
     width: '100%',
     zIndex: theme.zIndex.dropdown,
   } as CSSProperties,
diff --git a/src/components/Select/SelectMulti/SelectMulti.tsx b/src/components/Select/SelectMulti/SelectMulti.tsx
index 03d8e4e08..9577ab7b3 100644
--- a/src/components/Select/SelectMulti/SelectMulti.tsx
+++ b/src/components/Select/SelectMulti/SelectMulti.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useRef } from 'react'
 
 import { useFormControl, UseFormControlProps } from '../../../hooks/useFormControl'
 import { Omit } from '../../../util'
@@ -49,6 +49,8 @@ export function SelectMulti<T>(props: SelectMultiProps<T>) {
     ...rest
   } = props
 
+  const inputWrapperRef = useRef<HTMLDivElement>()
+
   const handleItemRemove = (removeItem: Function) => (item: T) => removeItem(item)
 
   const renderItem = ({ isSelected }: MultiSelectRenderProps<T>) => (item: T) => (
@@ -96,6 +98,7 @@ export function SelectMulti<T>(props: SelectMultiProps<T>) {
           return (
             <div>
               <SelectMultiInput<T>
+                wrapperRef={inputWrapperRef}
                 items={selectedItems}
                 {...rest}
                 placeholder={!selectedItems || selectedItems.length === 0 ? placeholder : undefined}
@@ -112,6 +115,7 @@ export function SelectMulti<T>(props: SelectMultiProps<T>) {
                 invalid={invalid}
               />
               <SelectDownshiftMenu
+                anchorRef={inputWrapperRef}
                 downshift={downshift}
                 items={visibleItems}
                 loading={loading}
diff --git a/src/components/Select/SelectMulti/SelectMultiInput.tsx b/src/components/Select/SelectMulti/SelectMultiInput.tsx
index 96564c5de..af54c9152 100644
--- a/src/components/Select/SelectMulti/SelectMultiInput.tsx
+++ b/src/components/Select/SelectMulti/SelectMultiInput.tsx
@@ -8,6 +8,7 @@ import { createStyleParts } from '../../TextField/TextInputBase'
 import { SelectMultiItem } from './SelectMultiItem'
 
 export interface SelectMultiInputProps<T> extends Omit<InputProps, 'style'> {
+  wrapperRef?: React.RefObject<HTMLDivElement>
   items: T[]
   invalid?: boolean
   clearable?: boolean
@@ -16,7 +17,7 @@ export interface SelectMultiInputProps<T> extends Omit<InputProps, 'style'> {
 }
 
 export function SelectMultiInput<T>(props: SelectMultiInputProps<T>) {
-  const { items, renderItem, onRemoveItem, invalid, disabled, clearable, ...rest } = props
+  const { wrapperRef, items, renderItem, onRemoveItem, invalid, disabled, clearable, ...rest } = props
 
   const inputRef = useRef<HTMLInputElement>()
 
@@ -31,7 +32,7 @@ export function SelectMultiInput<T>(props: SelectMultiInputProps<T>) {
   const wrapperClasses = css(classes.wrapper, invalid && classes.invalid, props.disabled && classes.disabled)
 
   return (
-    <div className={wrapperClasses} onClick={handleWrapperClick}>
+    <div ref={wrapperRef} className={wrapperClasses} onClick={handleWrapperClick}>
       {items &&
         items.map((item, key) => (
           <SelectMultiItem key={key} onRemove={handleRemove(item)} style={classes.item} disabled={disabled}>
diff --git a/src/components/Select/SelectSingle/SelectDownshiftMenu.tsx b/src/components/Select/SelectSingle/SelectDownshiftMenu.tsx
index 9b134de3c..e501c5a26 100644
--- a/src/components/Select/SelectSingle/SelectDownshiftMenu.tsx
+++ b/src/components/Select/SelectSingle/SelectDownshiftMenu.tsx
@@ -1,7 +1,9 @@
 import { ControllerStateAndHelpers } from 'downshift'
-import React, { CSSProperties } from 'react'
+import { PopperOptions } from 'popper.js'
+import React, { useRef } from 'react'
 
-import { useStyles } from '../../../styles'
+import usePopper from '../../../hooks/usePopper'
+import { composeRefs } from '../../../util/react'
 import { SelectEmptyItem, SelectLoadingItem, SelectMenu, SelectMenuItem } from '../SelectMenu'
 import { SelectCreateItem } from '../SelectMenu/SelectMenuItem'
 
@@ -9,8 +11,10 @@ export interface SelectDownshiftMenuProps<T> {
   items: T[]
   loading: boolean
   downshift: ControllerStateAndHelpers<T>
+  anchorRef: React.RefObject<HTMLElement>
   createNewItem?: boolean
   components?: Partial<SelectMenuComponents<T>>
+  popperProps?: PopperOptions
 
   /**
    * Render function used by each select item.
@@ -31,18 +35,36 @@ export function SelectDownshiftMenu<T>(props: SelectDownshiftMenuProps<T>) {
   const {
     items,
     loading: isLoading,
+    anchorRef,
     components,
     createNewItem,
+    popperProps,
     downshift: { isOpen, getMenuProps },
   } = props
 
-  const { classes } = useStyles(createStyles)
   const { CreateItem, LoadingItem, EmptyItem, Item } = { ...defaultComponents, ...components }
 
+  const menuRef = useRef<HTMLUListElement>()
+  const { style: popperStyle, placement } = usePopper(
+    {
+      anchorRef,
+      popperRef: menuRef,
+      ...popperProps,
+    },
+    [isOpen]
+  )
+
+  const { dropdownMenuRef, ...menuProps } = getMenuProps({ refKey: 'dropdownMenuRef' }, { suppressRefError: true })
+
   return (
-    <div className={classes.wrapper}>
+    <>
       {isOpen && (
-        <SelectMenu {...getMenuProps({ refKey: 'menuRef' })}>
+        <SelectMenu
+          {...menuProps}
+          menuRef={composeRefs(dropdownMenuRef, menuRef)}
+          style={{ ...popperStyle, width: anchorRef.current && anchorRef.current.clientWidth }}
+          data-placement={placement}
+        >
           {isLoading && <LoadingItem {...props} />}
 
           {!isLoading && createNewItem && (items || []).length > 0 && <CreateItem {...props} />}
@@ -52,7 +74,7 @@ export function SelectDownshiftMenu<T>(props: SelectDownshiftMenuProps<T>) {
           {items && items.map((item, index) => <Item key={index} index={index} item={item} {...props} />)}
         </SelectMenu>
       )}
-    </div>
+    </>
   )
 }
 
@@ -78,9 +100,3 @@ export const defaultComponents: SelectMenuComponents<any> = {
 SelectDownshiftMenu.defaultProps = {
   components: defaultComponents,
 } as Partial<SelectDownshiftMenuProps<any>>
-
-export const createStyles = () => ({
-  wrapper: {
-    position: 'relative',
-  } as CSSProperties,
-})
diff --git a/src/components/Select/SelectSingle/SelectSingle.tsx b/src/components/Select/SelectSingle/SelectSingle.tsx
index a4ea7b9bb..4a47ad46f 100644
--- a/src/components/Select/SelectSingle/SelectSingle.tsx
+++ b/src/components/Select/SelectSingle/SelectSingle.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useRef } from 'react'
 
 import { useFormControl, UseFormControlProps } from '../../../hooks/useFormControl'
 import { useStyles } from '../../../styles'
@@ -51,6 +51,8 @@ export function SelectSingle<T>(props: SelectSingleProps<T>) {
     ...rest
   } = props
 
+  const inputRef = useRef<HTMLInputElement>()
+
   const handleClear = (downshift: SelectDownshiftRenderProps<T>) => (
     e: React.MouseEvent<HTMLButtonElement, MouseEvent>
   ) => {
@@ -96,6 +98,7 @@ export function SelectSingle<T>(props: SelectSingleProps<T>) {
               <div>
                 <TextInput
                   icon={downshiftOpen ? 'angleUp' : 'angleDown'}
+                  inputRef={inputRef}
                   {...rest}
                   onBlur={handleInputBlur(downshift)}
                   onFocus={handleInputFocus(downshift)}
@@ -109,6 +112,7 @@ export function SelectSingle<T>(props: SelectSingleProps<T>) {
                 />
               </div>
               <SelectDownshiftMenu
+                anchorRef={inputRef}
                 downshift={downshift}
                 items={visibleItems}
                 loading={loading}
diff --git a/src/hooks/usePopper.ts b/src/hooks/usePopper.ts
index dba0da2f5..3657f8eac 100644
--- a/src/hooks/usePopper.ts
+++ b/src/hooks/usePopper.ts
@@ -5,6 +5,11 @@ const defaultOpts: PopperJS.PopperOptions = {
   placement: 'bottom',
   eventsEnabled: true,
   positionFixed: false,
+  modifiers: {
+    preventOverflow: {
+      boundariesElement: 'window',
+    },
+  },
 }
 
 const initialStyle = {


Test patch:
diff --git a/src/components/Select/SelectMenu/__snapshots__/SelectMenu.test.tsx.snap b/src/components/Select/SelectMenu/__snapshots__/SelectMenu.test.tsx.snap
index 8e92ff398..636f151a7 100644
--- a/src/components/Select/SelectMenu/__snapshots__/SelectMenu.test.tsx.snap
+++ b/src/components/Select/SelectMenu/__snapshots__/SelectMenu.test.tsx.snap
@@ -12,7 +12,6 @@ exports[`should render correctly 1`] = `
   max-height: 20rem;
   overflow-y: auto;
   overflow-x: hidden;
-  position: absolute;
   width: 100%;
   z-index: 1300;
 }
diff --git a/src/components/Select/SelectMulti/SelectMulti.test.tsx b/src/components/Select/SelectMulti/SelectMulti.test.tsx
index 2f30313c2..1c3b1adcb 100644
--- a/src/components/Select/SelectMulti/SelectMulti.test.tsx
+++ b/src/components/Select/SelectMulti/SelectMulti.test.tsx
@@ -1,4 +1,5 @@
 import { fireEvent, render } from '@testing-library/react'
+import { resetIdCounter } from 'downshift'
 import React from 'react'
 
 import { DefaultItemType } from '../SelectSingle'
@@ -28,6 +29,8 @@ function SelectTest(props: Partial<SelectMultiProps>) {
   )
 }
 
+beforeEach(() => resetIdCounter())
+
 it('should render correctly when closed', () => {
   const { container } = render(<SelectTest />)
   expect(container).toMatchSnapshot()
diff --git a/src/components/Select/SelectMulti/__snapshots__/SelectMulti.test.tsx.snap b/src/components/Select/SelectMulti/__snapshots__/SelectMulti.test.tsx.snap
index 186a93315..59c9e3fb3 100644
--- a/src/components/Select/SelectMulti/__snapshots__/SelectMulti.test.tsx.snap
+++ b/src/components/Select/SelectMulti/__snapshots__/SelectMulti.test.tsx.snap
@@ -98,10 +98,6 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
   background-color: #F0F0F5;
 }
 
-.emotion-3 {
-  position: relative;
-}
-
 .emotion-0 {
   font-weight: bold;
   display: block;
@@ -111,7 +107,7 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
 
 <div>
   <div
-    class="emotion-4"
+    class="emotion-3"
   >
     <label
       class="emotion-0"
@@ -122,7 +118,7 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
     <div
       aria-expanded="false"
       aria-haspopup="listbox"
-      aria-labelledby="downshift-13-label"
+      aria-labelledby="downshift-0-label"
       role="combobox"
     >
       <div
@@ -132,15 +128,12 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
           aria-autocomplete="list"
           autocomplete="off"
           class="emotion-1"
-          id="downshift-13-input"
+          id="downshift-0-input"
           placeholder="Select a value..."
           type="text"
           value=""
         />
       </div>
-      <div
-        class="emotion-3"
-      />
     </div>
   </div>
 </div>
@@ -244,10 +237,6 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
   background-color: #F0F0F5;
 }
 
-.emotion-3 {
-  position: relative;
-}
-
 .emotion-0 {
   font-weight: bold;
   display: block;
@@ -257,7 +246,7 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
 
 <div>
   <div
-    class="emotion-4"
+    class="emotion-3"
   >
     <label
       class="emotion-0"
@@ -279,15 +268,12 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
           aria-labelledby="label-abc"
           autocomplete="off"
           class="emotion-1"
-          id="downshift-14-input"
+          id="downshift-0-input"
           placeholder="Select a value..."
           type="text"
           value=""
         />
       </div>
-      <div
-        class="emotion-3"
-      />
     </div>
   </div>
 </div>
@@ -391,13 +377,9 @@ exports[`should render correctly when closed 1`] = `
   background-color: #F0F0F5;
 }
 
-.emotion-2 {
-  position: relative;
-}
-
 <div>
   <div
-    class="emotion-3"
+    class="emotion-2"
   >
     <div
       aria-expanded="false"
@@ -418,9 +400,6 @@ exports[`should render correctly when closed 1`] = `
           value=""
         />
       </div>
-      <div
-        class="emotion-2"
-      />
     </div>
   </div>
 </div>
@@ -524,10 +503,6 @@ exports[`should render correctly when opened 1`] = `
   background-color: #F0F0F5;
 }
 
-.emotion-28 {
-  position: relative;
-}
-
 .emotion-27 {
   list-style: none;
   margin: 0;
@@ -539,9 +514,13 @@ exports[`should render correctly when opened 1`] = `
   max-height: 20rem;
   overflow-y: auto;
   overflow-x: hidden;
-  position: absolute;
   width: 100%;
   z-index: 1300;
+  position: absolute;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  pointer-events: none;
 }
 
 .emotion-6 {
@@ -671,13 +650,13 @@ exports[`should render correctly when opened 1`] = `
 
 <div>
   <div
-    class="emotion-29"
+    class="emotion-28"
   >
     <div
       aria-expanded="true"
       aria-haspopup="listbox"
-      aria-labelledby="downshift-1-label"
-      aria-owns="downshift-1-menu"
+      aria-labelledby="downshift-0-label"
+      aria-owns="downshift-0-menu"
       role="combobox"
     >
       <div
@@ -685,151 +664,147 @@ exports[`should render correctly when opened 1`] = `
       >
         <input
           aria-autocomplete="list"
-          aria-controls="downshift-1-menu"
+          aria-controls="downshift-0-menu"
           autocomplete="off"
           class="emotion-0"
-          id="downshift-1-input"
+          id="downshift-0-input"
           placeholder="Select a value..."
           type="text"
           value=""
         />
       </div>
-      <div
-        class="emotion-28"
+      <ul
+        aria-labelledby="downshift-0-label"
+        class="emotion-27"
+        id="downshift-0-menu"
+        role="listbox"
       >
-        <ul
-          aria-labelledby="downshift-1-label"
-          class="emotion-27"
-          id="downshift-1-menu"
-          role="listbox"
+        <li
+          aria-selected="false"
+          class="emotion-6"
+          id="downshift-0-item-0"
+          role="option"
         >
-          <li
-            aria-selected="false"
-            class="emotion-6"
-            id="downshift-1-item-0"
-            role="option"
+          <div
+            class="emotion-5"
           >
-            <div
-              class="emotion-5"
+            <label
+              class="emotion-4"
             >
-              <label
-                class="emotion-4"
-              >
-                <input
-                  class="emotion-2"
-                  readonly=""
-                  tabindex="-1"
-                  type="checkbox"
-                />
-                <span
-                  class="emotion-3"
-                />
-              </label>
-              Apple
-            </div>
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-6"
-            id="downshift-1-item-1"
-            role="option"
+              <input
+                class="emotion-2"
+                readonly=""
+                tabindex="-1"
+                type="checkbox"
+              />
+              <span
+                class="emotion-3"
+              />
+            </label>
+            Apple
+          </div>
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-6"
+          id="downshift-0-item-1"
+          role="option"
+        >
+          <div
+            class="emotion-5"
           >
-            <div
-              class="emotion-5"
+            <label
+              class="emotion-4"
             >
-              <label
-                class="emotion-4"
-              >
-                <input
-                  class="emotion-2"
-                  readonly=""
-                  tabindex="-1"
-                  type="checkbox"
-                />
-                <span
-                  class="emotion-3"
-                />
-              </label>
-              Banana
-            </div>
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-6"
-            id="downshift-1-item-2"
-            role="option"
+              <input
+                class="emotion-2"
+                readonly=""
+                tabindex="-1"
+                type="checkbox"
+              />
+              <span
+                class="emotion-3"
+              />
+            </label>
+            Banana
+          </div>
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-6"
+          id="downshift-0-item-2"
+          role="option"
+        >
+          <div
+            class="emotion-5"
           >
-            <div
-              class="emotion-5"
+            <label
+              class="emotion-4"
             >
-              <label
-                class="emotion-4"
-              >
-                <input
-                  class="emotion-2"
-                  readonly=""
-                  tabindex="-1"
-                  type="checkbox"
-                />
-                <span
-                  class="emotion-3"
-                />
-              </label>
-              Grape
-            </div>
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-6"
-            id="downshift-1-item-3"
-            role="option"
+              <input
+                class="emotion-2"
+                readonly=""
+                tabindex="-1"
+                type="checkbox"
+              />
+              <span
+                class="emotion-3"
+              />
+            </label>
+            Grape
+          </div>
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-6"
+          id="downshift-0-item-3"
+          role="option"
+        >
+          <div
+            class="emotion-5"
           >
-            <div
-              class="emotion-5"
+            <label
+              class="emotion-4"
             >
-              <label
-                class="emotion-4"
-              >
-                <input
-                  class="emotion-2"
-                  readonly=""
-                  tabindex="-1"
-                  type="checkbox"
-                />
-                <span
-                  class="emotion-3"
-                />
-              </label>
-              Orange
-            </div>
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-6"
-            id="downshift-1-item-4"
-            role="option"
+              <input
+                class="emotion-2"
+                readonly=""
+                tabindex="-1"
+                type="checkbox"
+              />
+              <span
+                class="emotion-3"
+              />
+            </label>
+            Orange
+          </div>
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-6"
+          id="downshift-0-item-4"
+          role="option"
+        >
+          <div
+            class="emotion-5"
           >
-            <div
-              class="emotion-5"
+            <label
+              class="emotion-4"
             >
-              <label
-                class="emotion-4"
-              >
-                <input
-                  class="emotion-2"
-                  readonly=""
-                  tabindex="-1"
-                  type="checkbox"
-                />
-                <span
-                  class="emotion-3"
-                />
-              </label>
-              Pear
-            </div>
-          </li>
-        </ul>
-      </div>
+              <input
+                class="emotion-2"
+                readonly=""
+                tabindex="-1"
+                type="checkbox"
+              />
+              <span
+                class="emotion-3"
+              />
+            </label>
+            Pear
+          </div>
+        </li>
+      </ul>
     </div>
   </div>
 </div>
diff --git a/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap b/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap
index 8b238a58e..226397a9f 100644
--- a/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap
+++ b/src/components/Select/SelectSingle/__snapshots__/SelectSingle.test.tsx.snap
@@ -166,10 +166,6 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
   font-size: 1.5rem;
 }
 
-.emotion-6 {
-  position: relative;
-}
-
 .emotion-0 {
   font-weight: bold;
   display: block;
@@ -179,7 +175,7 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
 
 <div>
   <div
-    class="emotion-7"
+    class="emotion-6"
   >
     <label
       class="emotion-0"
@@ -191,7 +187,7 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
       aria-expanded="false"
       aria-haspopup="listbox"
       aria-labelledby="downshift-0-label"
-      class="emotion-7"
+      class="emotion-6"
       role="combobox"
     >
       <div>
@@ -233,9 +229,6 @@ exports[`input label label should have a htmlFor prop equals to the used id 1`]
           </span>
         </div>
       </div>
-      <div
-        class="emotion-6"
-      />
     </div>
   </div>
 </div>
@@ -407,10 +400,6 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
   font-size: 1.5rem;
 }
 
-.emotion-6 {
-  position: relative;
-}
-
 .emotion-0 {
   font-weight: bold;
   display: block;
@@ -420,7 +409,7 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
 
 <div>
   <div
-    class="emotion-7"
+    class="emotion-6"
   >
     <label
       class="emotion-0"
@@ -432,7 +421,7 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
       aria-expanded="false"
       aria-haspopup="listbox"
       aria-labelledby="label-abc"
-      class="emotion-7"
+      class="emotion-6"
       role="combobox"
     >
       <div>
@@ -475,9 +464,6 @@ exports[`input label should use aria-labelledby equals to an auto-assigned label
           </span>
         </div>
       </div>
-      <div
-        class="emotion-6"
-      />
     </div>
   </div>
 </div>
@@ -649,19 +635,15 @@ exports[`should render correctly when closed 1`] = `
   font-size: 1.5rem;
 }
 
-.emotion-5 {
-  position: relative;
-}
-
 <div>
   <div
-    class="emotion-6"
+    class="emotion-5"
   >
     <div
       aria-expanded="false"
       aria-haspopup="listbox"
       aria-labelledby="downshift-0-label"
-      class="emotion-6"
+      class="emotion-5"
       role="combobox"
     >
       <div>
@@ -703,9 +685,6 @@ exports[`should render correctly when closed 1`] = `
           </span>
         </div>
       </div>
-      <div
-        class="emotion-5"
-      />
     </div>
   </div>
 </div>
@@ -877,10 +856,6 @@ exports[`should render correctly when opened 1`] = `
   font-size: 1.5rem;
 }
 
-.emotion-11 {
-  position: relative;
-}
-
 .emotion-10 {
   list-style: none;
   margin: 0;
@@ -892,9 +867,13 @@ exports[`should render correctly when opened 1`] = `
   max-height: 20rem;
   overflow-y: auto;
   overflow-x: hidden;
-  position: absolute;
   width: 100%;
   z-index: 1300;
+  position: absolute;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  pointer-events: none;
 }
 
 .emotion-5 {
@@ -925,14 +904,14 @@ exports[`should render correctly when opened 1`] = `
 
 <div>
   <div
-    class="emotion-12"
+    class="emotion-11"
   >
     <div
       aria-expanded="true"
       aria-haspopup="listbox"
       aria-labelledby="downshift-0-label"
       aria-owns="downshift-0-menu"
-      class="emotion-12"
+      class="emotion-11"
       role="combobox"
     >
       <div>
@@ -975,57 +954,53 @@ exports[`should render correctly when opened 1`] = `
           </span>
         </div>
       </div>
-      <div
-        class="emotion-11"
+      <ul
+        aria-labelledby="downshift-0-label"
+        class="emotion-10"
+        id="downshift-0-menu"
+        role="listbox"
       >
-        <ul
-          aria-labelledby="downshift-0-label"
-          class="emotion-10"
-          id="downshift-0-menu"
-          role="listbox"
+        <li
+          aria-selected="false"
+          class="emotion-5"
+          id="downshift-0-item-0"
+          role="option"
         >
-          <li
-            aria-selected="false"
-            class="emotion-5"
-            id="downshift-0-item-0"
-            role="option"
-          >
-            Apple
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-5"
-            id="downshift-0-item-1"
-            role="option"
-          >
-            Banana
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-5"
-            id="downshift-0-item-2"
-            role="option"
-          >
-            Grape
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-5"
-            id="downshift-0-item-3"
-            role="option"
-          >
-            Orange
-          </li>
-          <li
-            aria-selected="false"
-            class="emotion-5"
-            id="downshift-0-item-4"
-            role="option"
-          >
-            Pear
-          </li>
-        </ul>
-      </div>
+          Apple
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-5"
+          id="downshift-0-item-1"
+          role="option"
+        >
+          Banana
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-5"
+          id="downshift-0-item-2"
+          role="option"
+        >
+          Grape
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-5"
+          id="downshift-0-item-3"
+          role="option"
+        >
+          Orange
+        </li>
+        <li
+          aria-selected="false"
+          class="emotion-5"
+          id="downshift-0-item-4"
+          role="option"
+        >
+          Pear
+        </li>
+      </ul>
     </div>
   </div>
 </div>
diff --git a/src/components/SelectInline/SelectInline.test.tsx b/src/components/SelectInline/SelectInline.test.tsx
index 1d20861fb..b23a1cd39 100644
--- a/src/components/SelectInline/SelectInline.test.tsx
+++ b/src/components/SelectInline/SelectInline.test.tsx
@@ -1,4 +1,5 @@
 import { fireEvent, render, wait } from '@testing-library/react'
+import { resetIdCounter } from 'downshift'
 import React from 'react'
 
 import { DefaultItemType } from '../Select/SelectSingle'
@@ -25,6 +26,8 @@ const createSelectInline = (props?: Partial<SelectInlineProps<DefaultItemType>>)
   />
 )
 
+beforeEach(() => resetIdCounter())
+
 describe('SelectInline', () => {
   it('should render correctly when closed', () => {
     const { container } = render(createSelectInline())
diff --git a/src/components/SelectInline/__snapshots__/SelectInline.test.tsx.snap b/src/components/SelectInline/__snapshots__/SelectInline.test.tsx.snap
index b481025d1..08f06d3e8 100644
--- a/src/components/SelectInline/__snapshots__/SelectInline.test.tsx.snap
+++ b/src/components/SelectInline/__snapshots__/SelectInline.test.tsx.snap
@@ -5,11 +5,11 @@ exports[`SelectInline should render correctly when closed 1`] = `
   display: inline-block;
 }
 
-.emotion-18 {
+.emotion-17 {
   display: inline-block;
 }
 
-.emotion-18 [data-visible] {
+.emotion-17 [data-visible] {
   box-shadow: 0 2px 4px -1px rgba(0,0,0,0.2),0 1px 10px 0 rgba(0,0,0,0.12),0 4px 5px 0 rgba(0,0,0,0.14);
 }
 
@@ -85,7 +85,7 @@ exports[`SelectInline should render correctly when closed 1`] = `
   margin-left: 0.5rem;
 }
 
-.emotion-17 {
+.emotion-16 {
   -webkit-transition: opacity .2s;
   transition: opacity .2s;
   z-index: 1200;
@@ -94,20 +94,20 @@ exports[`SelectInline should render correctly when closed 1`] = `
   opacity: 0;
 }
 
-.emotion-15 {
+.emotion-14 {
   border: 1px solid #D3D4DD;
   background-color: #FFFFFF;
 }
 
-.emotion-15 > div:first-of-type {
+.emotion-14 > div:first-of-type {
   padding: 0.5rem;
 }
 
-.emotion-15 ul > li:first-of-type {
+.emotion-14 ul > li:first-of-type {
   border-top: 1px solid #D3D4DD;
 }
 
-.emotion-15 div > ul {
+.emotion-14 div > ul {
   position: static;
   box-shadow: none;
   border: none;
@@ -274,10 +274,6 @@ exports[`SelectInline should render correctly when closed 1`] = `
   box-shadow: none;
 }
 
-.emotion-14 {
-  position: relative;
-}
-
 .emotion-13 {
   list-style: none;
   margin: 0;
@@ -289,9 +285,13 @@ exports[`SelectInline should render correctly when closed 1`] = `
   max-height: 20rem;
   overflow-y: auto;
   overflow-x: hidden;
-  position: absolute;
   width: 100%;
   z-index: 1300;
+  position: absolute;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  pointer-events: none;
 }
 
 .emotion-9 {
@@ -322,7 +322,7 @@ exports[`SelectInline should render correctly when closed 1`] = `
 
 <div>
   <div
-    class="emotion-18"
+    class="emotion-17"
   >
     <div
       class="emotion-3"
@@ -353,19 +353,19 @@ exports[`SelectInline should render correctly when closed 1`] = `
       </button>
     </div>
     <div
-      class="emotion-17"
+      class="emotion-16"
       data-visible="false"
       style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none;"
     >
       <div
-        class="emotion-16"
+        class="emotion-15"
       >
         <div
           aria-expanded="true"
           aria-haspopup="listbox"
           aria-labelledby="downshift-0-label"
           aria-owns="downshift-0-menu"
-          class="emotion-15"
+          class="emotion-14"
           role="combobox"
         >
           <div>
@@ -408,49 +408,45 @@ exports[`SelectInline should render correctly when closed 1`] = `
               </span>
             </div>
           </div>
-          <div
-            class="emotion-14"
+          <ul
+            aria-labelledby="downshift-0-label"
+            class="emotion-13"
+            id="downshift-0-menu"
+            role="listbox"
           >
-            <ul
-              aria-labelledby="downshift-0-label"
-              class="emotion-13"
-              id="downshift-0-menu"
-              role="listbox"
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-0"
+              role="option"
             >
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-0-item-0"
-                role="option"
-              >
-                Value #001
-              </li>
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-0-item-1"
-                role="option"
-              >
-                Value #002
-              </li>
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-0-item-2"
-                role="option"
-              >
-                Value #003
-              </li>
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-0-item-3"
-                role="option"
-              >
-                Value #004
-              </li>
-            </ul>
-          </div>
+              Value #001
+            </li>
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-1"
+              role="option"
+            >
+              Value #002
+            </li>
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-2"
+              role="option"
+            >
+              Value #003
+            </li>
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-3"
+              role="option"
+            >
+              Value #004
+            </li>
+          </ul>
         </div>
       </div>
     </div>
@@ -463,11 +459,11 @@ exports[`SelectInline should render correctly when opened 1`] = `
   display: inline-block;
 }
 
-.emotion-18 {
+.emotion-17 {
   display: inline-block;
 }
 
-.emotion-18 [data-visible] {
+.emotion-17 [data-visible] {
   box-shadow: 0 2px 4px -1px rgba(0,0,0,0.2),0 1px 10px 0 rgba(0,0,0,0.12),0 4px 5px 0 rgba(0,0,0,0.14);
 }
 
@@ -543,20 +539,20 @@ exports[`SelectInline should render correctly when opened 1`] = `
   margin-left: 0.5rem;
 }
 
-.emotion-15 {
+.emotion-14 {
   border: 1px solid #D3D4DD;
   background-color: #FFFFFF;
 }
 
-.emotion-15 > div:first-of-type {
+.emotion-14 > div:first-of-type {
   padding: 0.5rem;
 }
 
-.emotion-15 ul > li:first-of-type {
+.emotion-14 ul > li:first-of-type {
   border-top: 1px solid #D3D4DD;
 }
 
-.emotion-15 div > ul {
+.emotion-14 div > ul {
   position: static;
   box-shadow: none;
   border: none;
@@ -723,10 +719,6 @@ exports[`SelectInline should render correctly when opened 1`] = `
   box-shadow: none;
 }
 
-.emotion-14 {
-  position: relative;
-}
-
 .emotion-13 {
   list-style: none;
   margin: 0;
@@ -738,9 +730,13 @@ exports[`SelectInline should render correctly when opened 1`] = `
   max-height: 20rem;
   overflow-y: auto;
   overflow-x: hidden;
-  position: absolute;
   width: 100%;
   z-index: 1300;
+  position: absolute;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  pointer-events: none;
 }
 
 .emotion-9 {
@@ -769,7 +765,7 @@ exports[`SelectInline should render correctly when opened 1`] = `
   box-shadow: inset 0 0 0 2px #0069D0;
 }
 
-.emotion-17 {
+.emotion-16 {
   -webkit-transition: opacity .2s;
   transition: opacity .2s;
   z-index: 1200;
@@ -781,7 +777,7 @@ exports[`SelectInline should render correctly when opened 1`] = `
 <body>
   <div>
     <div
-      class="emotion-18"
+      class="emotion-17"
     >
       <div
         class="emotion-3"
@@ -812,19 +808,19 @@ exports[`SelectInline should render correctly when opened 1`] = `
         </button>
       </div>
       <div
-        class="emotion-17"
+        class="emotion-16"
         data-visible="true"
         style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none;"
       >
         <div
-          class="emotion-16"
+          class="emotion-15"
         >
           <div
             aria-expanded="true"
             aria-haspopup="listbox"
-            aria-labelledby="downshift-3-label"
-            aria-owns="downshift-3-menu"
-            class="emotion-15"
+            aria-labelledby="downshift-0-label"
+            aria-owns="downshift-0-menu"
+            class="emotion-14"
             role="combobox"
           >
             <div>
@@ -833,10 +829,10 @@ exports[`SelectInline should render correctly when opened 1`] = `
               >
                 <input
                   aria-autocomplete="list"
-                  aria-controls="downshift-3-menu"
+                  aria-controls="downshift-0-menu"
                   autocomplete="off"
                   class="emotion-4"
-                  id="downshift-3-input"
+                  id="downshift-0-input"
                   placeholder="Search for a value"
                   type="text"
                   value=""
@@ -867,49 +863,45 @@ exports[`SelectInline should render correctly when opened 1`] = `
                 </span>
               </div>
             </div>
-            <div
-              class="emotion-14"
+            <ul
+              aria-labelledby="downshift-0-label"
+              class="emotion-13"
+              id="downshift-0-menu"
+              role="listbox"
             >
-              <ul
-                aria-labelledby="downshift-3-label"
-                class="emotion-13"
-                id="downshift-3-menu"
-                role="listbox"
+              <li
+                aria-selected="false"
+                class="emotion-9"
+                id="downshift-0-item-0"
+                role="option"
               >
-                <li
-                  aria-selected="false"
-                  class="emotion-9"
-                  id="downshift-3-item-0"
-                  role="option"
-                >
-                  Value #001
-                </li>
-                <li
-                  aria-selected="false"
-                  class="emotion-9"
-                  id="downshift-3-item-1"
-                  role="option"
-                >
-                  Value #002
-                </li>
-                <li
-                  aria-selected="false"
-                  class="emotion-9"
-                  id="downshift-3-item-2"
-                  role="option"
-                >
-                  Value #003
-                </li>
-                <li
-                  aria-selected="false"
-                  class="emotion-9"
-                  id="downshift-3-item-3"
-                  role="option"
-                >
-                  Value #004
-                </li>
-              </ul>
-            </div>
+                Value #001
+              </li>
+              <li
+                aria-selected="false"
+                class="emotion-9"
+                id="downshift-0-item-1"
+                role="option"
+              >
+                Value #002
+              </li>
+              <li
+                aria-selected="false"
+                class="emotion-9"
+                id="downshift-0-item-2"
+                role="option"
+              >
+                Value #003
+              </li>
+              <li
+                aria-selected="false"
+                class="emotion-9"
+                id="downshift-0-item-3"
+                role="option"
+              >
+                Value #004
+              </li>
+            </ul>
           </div>
         </div>
       </div>
@@ -923,11 +915,11 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
   display: inline-block;
 }
 
-.emotion-18 {
+.emotion-17 {
   display: inline-block;
 }
 
-.emotion-18 [data-visible] {
+.emotion-17 [data-visible] {
   box-shadow: 0 2px 4px -1px rgba(0,0,0,0.2),0 1px 10px 0 rgba(0,0,0,0.12),0 4px 5px 0 rgba(0,0,0,0.14);
 }
 
@@ -1003,7 +995,7 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
   margin-left: 0.5rem;
 }
 
-.emotion-17 {
+.emotion-16 {
   -webkit-transition: opacity .2s;
   transition: opacity .2s;
   z-index: 1200;
@@ -1012,20 +1004,20 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
   opacity: 0;
 }
 
-.emotion-15 {
+.emotion-14 {
   border: 1px solid #D3D4DD;
   background-color: #FFFFFF;
 }
 
-.emotion-15 > div:first-of-type {
+.emotion-14 > div:first-of-type {
   padding: 0.5rem;
 }
 
-.emotion-15 ul > li:first-of-type {
+.emotion-14 ul > li:first-of-type {
   border-top: 1px solid #D3D4DD;
 }
 
-.emotion-15 div > ul {
+.emotion-14 div > ul {
   position: static;
   box-shadow: none;
   border: none;
@@ -1192,10 +1184,6 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
   box-shadow: none;
 }
 
-.emotion-14 {
-  position: relative;
-}
-
 .emotion-13 {
   list-style: none;
   margin: 0;
@@ -1207,9 +1195,13 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
   max-height: 20rem;
   overflow-y: auto;
   overflow-x: hidden;
-  position: absolute;
   width: 100%;
   z-index: 1300;
+  position: absolute;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  pointer-events: none;
 }
 
 .emotion-9 {
@@ -1240,7 +1232,7 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
 
 <div>
   <div
-    class="emotion-18"
+    class="emotion-17"
   >
     <div
       class="emotion-3"
@@ -1272,19 +1264,19 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
       </button>
     </div>
     <div
-      class="emotion-17"
+      class="emotion-16"
       data-visible="false"
       style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none;"
     >
       <div
-        class="emotion-16"
+        class="emotion-15"
       >
         <div
           aria-expanded="true"
           aria-haspopup="listbox"
-          aria-labelledby="downshift-1-label"
-          aria-owns="downshift-1-menu"
-          class="emotion-15"
+          aria-labelledby="downshift-0-label"
+          aria-owns="downshift-0-menu"
+          class="emotion-14"
           role="combobox"
         >
           <div>
@@ -1293,10 +1285,10 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
             >
               <input
                 aria-autocomplete="list"
-                aria-controls="downshift-1-menu"
+                aria-controls="downshift-0-menu"
                 autocomplete="off"
                 class="emotion-4"
-                id="downshift-1-input"
+                id="downshift-0-input"
                 placeholder="Search for a value"
                 type="text"
                 value=""
@@ -1327,49 +1319,45 @@ exports[`SelectInline should render correctly with button placeholder 1`] = `
               </span>
             </div>
           </div>
-          <div
-            class="emotion-14"
+          <ul
+            aria-labelledby="downshift-0-label"
+            class="emotion-13"
+            id="downshift-0-menu"
+            role="listbox"
           >
-            <ul
-              aria-labelledby="downshift-1-label"
-              class="emotion-13"
-              id="downshift-1-menu"
-              role="listbox"
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-0"
+              role="option"
             >
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-1-item-0"
-                role="option"
-              >
-                Value #001
-              </li>
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-1-item-1"
-                role="option"
-              >
-                Value #002
-              </li>
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-1-item-2"
-                role="option"
-              >
-                Value #003
-              </li>
-              <li
-                aria-selected="false"
-                class="emotion-9"
-                id="downshift-1-item-3"
-                role="option"
-              >
-                Value #004
-              </li>
-            </ul>
-          </div>
+              Value #001
+            </li>
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-1"
+              role="option"
+            >
+              Value #002
+            </li>
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-2"
+              role="option"
+            >
+              Value #003
+            </li>
+            <li
+              aria-selected="false"
+              class="emotion-9"
+              id="downshift-0-item-3"
+              role="option"
+            >
+              Value #004
+            </li>
+          </ul>
         </div>
       </div>
     </div>