Import
import { Dropdown } from '@dnb/eufemia'
Description
The Dropdown component is a fully custom-made component. This allows us to change its form based on context (small screens, touch devices, etc.).
Relevant links
When to use
Use a dropdown when you need to provide many options to the user but don't have space to display them all. The hidden options should only appear when the user requests them, reducing visual clutter.
- When space is limited
- When you want to reduce visual clutter
- When it's intuitive for users to request hidden content
When not to use
- Do not use a dropdown if you have only a few options that could be shown using Radio buttons or ToggleButtons.
Note: This pattern can be constructed in various ways to achieve a similar effect—from using the HTML select element to custom building with divs, spans, and JavaScript.
Accessibility
When preventSelection is true, the Dropdown will use role="menu", instead of role="listbox" for better screen reader support.
Custom size
You can change the width of the Dropdown component with CSS by using:
.dnb-dropdown {--dropdown-width: 20rem; /* custom width */}
You can also set the width directly, but then it has to be defined like so (including min-width):
/** Because of the included label/status etc. we target the "__shell" */.dnb-dropdown__shell {width: 10rem;}/** In order to change only the drawer-list width */.dnb-dropdown .dnb-drawer-list__root {width: 10rem;}/** If using popup style (no title) */.dnb-dropdown--is-popup .dnb-drawer-list__root {width: 10rem;}
Demos
Default dropdown
No value is defined, but a title is given.
const data = [ // Every data item can, beside "content" - contain what ever { // (optional) can be what ever selectedKey: 'key_0', // (optional) is show instead of "content", once selected selectedValue: 'Item 1 Value', // Item content as a string or array content: 'Item 1 Content', }, { selectedKey: 'key_1', content: ['Item 2 Value', 'Item 2 Content'], }, { selectedValue: ( <NumberFormat.BankAccountNumber alwaysSelectAll> 11345678962 </NumberFormat.BankAccountNumber> ), content: [ <NumberFormat.BankAccountNumber key="ban" alwaysSelectAll> 11345678962 </NumberFormat.BankAccountNumber>, 'Bank account number', ], }, { selectedKey: 'key_2', selectedValue: 'Item 3 Value', content: ['Item 3 Content A', 'Item 3 Content B'], }, { selectedKey: 'key_3', selectedValue: 'Item 4 Value', content: ['Item 4 Content A', <>Custom Component</>], }, ] render( <Dropdown data={data} label="Label" title="Please select a value" onChange={({ data }) => { console.log('onChange', data) }} /> )
Dropdown with different item content directions
<Dropdown label="Label" data={[ ['Vertical', 'alignment'], <> <P weight="medium">Vertical</P> <P>alignment</P> </>, <Dropdown.HorizontalItem key="item-1"> <P weight="medium" right="x-small"> Horizontal </P> <P>alignment</P> </Dropdown.HorizontalItem>, ]} />
Icon on left side
<Dropdown label="Label" iconPosition="left" data={data} value={3} skipPortal={true} onChange={({ data: selectedDataItem }) => { console.log('onChange', selectedDataItem) }} onOpen={() => { console.log('onOpen') }} />
Dropdown as tertiary variant
<Dropdown variant="tertiary" direction="bottom" independentWidth={true} iconPosition="left" align="left" data={data} />
Dropdown in different sizes
Four sizes are available: small, default, medium and large
<Flex.Vertical> <Dropdown label="Label" size="default" data={() => data} /> <Dropdown label="Label" size="medium" data={() => data} /> <Dropdown label="Label" size="large" data={() => data} /> </Flex.Vertical>
Custom width
const CustomWidthOne = styled(Dropdown)` .dnb-dropdown__shell { width: 10rem; } ` const CustomWidthTwo = styled(Dropdown)` &.dnb-dropdown--is-popup .dnb-drawer-list__root { width: 12rem; } ` const CustomWidthThree = styled(Dropdown)` /** Change the "__shell" width */ .dnb-dropdown__shell { width: 10rem; } /** Change the "__list" width */ .dnb-drawer-list__root { width: 20rem; } ` const CustomWidthFour = styled(Dropdown)` width: 60%; min-width: 224px; /** 14rem (please use pixels on min-width!) */ max-width: 25rem; /** In case we have a label */ .dnb-form-label + .dnb-dropdown__inner { width: 100%; } ` render( <Flex.Vertical> <CustomWidthOne label="Label" size="default" iconPosition="left" data={data} /> <CustomWidthTwo label="Label" size="small" preventSelection title={null} data={data} /> <CustomWidthThree label="Label" size="large" align="right" data={data} /> <CustomWidthFour title="Min and max width" stretch={true} data={data} /> </Flex.Vertical> )
Dropdown with status
And vertical label layout.
<Dropdown data={data} label="Label" status="Message to the user" />
Findable list
With long list to make it scrollable and searchable
const scrollableData = [ { content: 'A', }, { content: 'B', }, { selectedValue: ( <NumberFormat.BankAccountNumber alwaysSelectAll> 11345678962 </NumberFormat.BankAccountNumber> ), content: [ <NumberFormat.BankAccountNumber key="ban-1" alwaysSelectAll> 11345678962 </NumberFormat.BankAccountNumber>, 'C', ], }, { selectedValue: ( <NumberFormat.BankAccountNumber alwaysSelectAll> 15349648901 </NumberFormat.BankAccountNumber> ), content: [ <NumberFormat.BankAccountNumber key="ban-2" alwaysSelectAll> 15349648901 </NumberFormat.BankAccountNumber>, 'D', ], }, { content: 'E', }, { selectedKey: 'key_1', selectedValue: 'Find me by keypress', content: ['F', 'F', 'F', 'F'], }, { content: 'G', }, { content: 'H', }, ] render( <Dropdown data={scrollableData} value="key_1" // use either index (5) or selectedKey: 'key_1' label="Label" /> )
Disabled dropdown
<Dropdown disabled data={['Disabled Dropdown']} label="Label" />
Individual options can also be disabled.
<Dropdown data={[ { content: 'Item 1 Content', }, { content: 'Item 2 Content', disabled: true, }, { content: 'Item 3 Content', disabled: true, }, { content: 'Item 4 Content A', }, ]} label="Label" />
Disabled tertiary dropdown
<Dropdown disabled variant="tertiary" data={['Disabled Dropdown']} label="Disabled tertiary dropdown" />
Customized Dropdown
An example of how you can customize the look of your Dropdown
const styles = { customTrigger: { backgroundColor: '#d4ecc5', color: '#14555a', border: 'none', borderRadius: '8px', padding: '8px 16px', fontWeight: 600, }, customMenuItem: { display: 'flex', flexFlow: 'row nowrap', justifyContent: 'space-between', alignItems: 'center', }, customMenuItemTitle: { display: 'flex', flexFlow: 'column', gap: '0.5rem', }, } const MenuItem = ({ title, content, key }) => ( <span style={styles.customMenuItem} key="item-1"> <span style={styles.customMenuItemTitle}> {title} <span>{content}</span> </span> <Icon icon={chevron_right} /> </span> ) const data = { accounts: ( <MenuItem key="item-1" title="Accounts" content={'Bills, Savings'} /> ), loans: <MenuItem key="item-2" title="Loans" content={'Mortgage, Car'} />, cards: ( <MenuItem key="item-3" title="Cards" content={'Visa, Mastercard'} /> ), stocks: ( <MenuItem key="item-4" title="Stocks" content={'Nvidia, Apple'} /> ), } render( <Dropdown data={data} preventSelection triggerElement={(props) => ( <button {...props} style={styles.customTrigger}> <Icon icon={newspaper} /> Custom trigger{' '} <Icon icon={chevron_down} /> </button> )} /> )
DrawerList opened
Only to visualize and used for visual testing
Groups
If an item has a groupIndex property, it will use the groups in the groups property. Only the first group can be without title, all other groups must have a title.
<Dropdown groups={[undefined, 'Pets', 'Cars']} data={[ { groupIndex: 0, content: 'Default 2', }, { groupIndex: 0, content: 'Default 1', }, { groupIndex: 1, content: 'Cat', }, { groupIndex: 1, content: 'Dog', }, { groupIndex: 2, content: 'Jeep', }, { groupIndex: 2, content: 'Van', }, ]} />