Components
Dropdown
Dropdown is a generic dropdown list. It lays the foundation for building menus and lists.
React
Unable to parse html
const Preview = () => { return ( <Dropdown.TriggerContext> <Dropdown.Trigger>Dropdown</Dropdown.Trigger> <Dropdown placement='bottom-end'> <Dropdown.Heading>First heading</Dropdown.Heading> <Dropdown.List> <Dropdown.Item> <Dropdown.Button>Button 1.1</Dropdown.Button> </Dropdown.Item> <Dropdown.Item> <Dropdown.Button>Button 1.2</Dropdown.Button> </Dropdown.Item> </Dropdown.List> <Dropdown.Heading>Second heading</Dropdown.Heading> <Dropdown.List> <Dropdown.Item> <Dropdown.Button>Button 2.1</Dropdown.Button> </Dropdown.Item> <Dropdown.Item> <Dropdown.Button>Button 2.2</Dropdown.Button> </Dropdown.Item> </Dropdown.List> </Dropdown> </Dropdown.TriggerContext> ); }; render(<Preview />)
- id
- Description
id to connect the trigger with the popover - required when not using Popover.Context.
- Type
string
- open
- Description
When a boolean is provided, the popover will be controlled.
- Type
boolean- Default
undefined
- onOpen
- Description
Callback when the popover wants to open.
- Type
(() => void)
- onClose
- Description
Callback when the popover wants to close.
- Type
(() => void)
- autoPlacement
- Description
Whether to enable auto placement.
- Type
boolean- Default
true
- asChild
- Description
Change the default rendered element for the one passed as a child, merging their props and behavior.
- Type
boolean- Default
false
- placement
- Description
The placement of the dropdown
- Type
Placement- Default
bottom-end
| Name | Type | Default | Description |
|---|---|---|---|
| id | string | - | id to connect the trigger with the popover - required when not using Popover.Context. |
| open | boolean | undefined | When a boolean is provided, the popover will be controlled. |
| onOpen | (() => void) | - | Callback when the popover wants to open. |
| onClose | (() => void) | - | Callback when the popover wants to close. |
| autoPlacement | boolean | true | Whether to enable auto placement. |
| asChild | boolean | false | Change the default rendered element for the one passed as a child, merging their props and behavior. |
| placement | Placement | bottom-end | The placement of the dropdown |
DropdownButton
- type
- Description
Specify the type of button. Unset when `asChild` is true
- Type
"submit" | "reset" | "button"- Default
'button'
- icon
- Description
Toggle icon only styling, pass icon as children When combined with loading, the loading-icon will be shown instead of the icon.
- Type
boolean- Default
false
- loading
- Description
Toggle loading state. Pass an element if you want to display a custom loader.
- Type
ReactNode- Default
false
- asChild
- Description
Change the default rendered element for the one passed as a child, merging their props and behavior.
- Type
boolean- Default
false
| Name | Type | Default | Description |
|---|---|---|---|
| type | "submit" | "reset" | "button" | 'button' | Specify the type of button. Unset when `asChild` is true |
| icon | boolean | false | Toggle icon only styling, pass icon as children When combined with loading, the loading-icon will be shown instead of the icon. |
| loading | ReactNode | false | Toggle loading state. Pass an element if you want to display a custom loader. |
| asChild | boolean | false | Change the default rendered element for the one passed as a child, merging their props and behavior. |
DropdownHeading
- level
- Description
Heading level. This will translate into any h1-6 level unless `asChild` is `true`
- Type
1 | 2 | 3 | 4 | 5 | 6- Default
2
- asChild
- Description
Change the default rendered element for the one passed as a child, merging their props and behavior.
- Type
boolean- Default
false
| Name | Type | Default | Description |
|---|---|---|---|
| level | 1 | 2 | 3 | 4 | 5 | 6 | 2 | Heading level. This will translate into any h1-6 level unless `asChild` is `true` |
| asChild | boolean | false | Change the default rendered element for the one passed as a child, merging their props and behavior. |
DropdownTrigger
- inline
- Description
Will render the trigger as inline text.
- Type
boolean- Default
false false
- asChild
- Description
Change the default rendered element for the one passed as a child, merging their props and behavior.
- Type
boolean- Default
false false
- variant
- Description
Specify which variant to use
- Type
"primary" | "secondary" | "tertiary"- Default
'primary'
- icon
- Description
Toggle icon only styling, pass icon as children When combined with loading, the loading-icon will be shown instead of the icon.
- Type
boolean- Default
false
- loading
- Description
Toggle loading state. Pass an element if you want to display a custom loader.
- Type
ReactNode- Default
false
- type
- Description
Specify the type of button. Unset when `asChild` is true
- Type
"button" | "submit" | "reset"- Default
'button'
| Name | Type | Default | Description |
|---|---|---|---|
| inline | boolean | false false | Will render the trigger as inline text. |
| asChild | boolean | false false | Change the default rendered element for the one passed as a child, merging their props and behavior. |
| variant | "primary" | "secondary" | "tertiary" | 'primary' | Specify which variant to use |
| icon | boolean | false | Toggle icon only styling, pass icon as children When combined with loading, the loading-icon will be shown instead of the icon. |
| loading | ReactNode | false | Toggle loading state. Pass an element if you want to display a custom loader. |
| type | "button" | "submit" | "reset" | 'button' | Specify the type of button. Unset when `asChild` is true |
Usage
Dropdown uses Popover internally.
React and popovertarget
When you use popover without Dropdown.TriggerContext, you link yourself trigger and popover.
Then popovertarget is used in lowercase, so that all versions of React correctly render the attribute.
When using @digdir/designsystemet-react we extend @types/react-dom to accept this.
Polyfill
Dropdown uses the Popover API (mozilla.org). This API is classified as Baseline:
Newly available (mozilla.org) as of April 2024,
with Firefox as the last browser to add it. In some cases, you may find that users are locked to older browser versions for various reasons, and then it may be appropriate to add a Popover-Polyfill (github.com) to ensure that Dropdown works for everyone.
Examples
Controlled
If you submit open, then you use Dropdown controlled. You can use onClose to get notified when Dropdown wants to close.
React
Unable to parse html
const ControlledEn = () => { const [open, setOpen] = useState(false); return ( <Dropdown.TriggerContext> <Dropdown.Trigger onClick={() => setOpen(!open)}> Dropdown {open ? <ChevronDownIcon aria-hidden /> : <ChevronUpIcon aria-hidden />} </Dropdown.Trigger> <Dropdown open={open} onClose={() => setOpen(false)}> <Dropdown.List> <Dropdown.Item> <Dropdown.Button onClick={() => setOpen(false)}> Click me to close </Dropdown.Button> </Dropdown.Item> <Dropdown.Item> <Dropdown.Button onClick={() => setOpen(false)}> I close too </Dropdown.Button> </Dropdown.Item> </Dropdown.List> </Dropdown> </Dropdown.TriggerContext> ); }; render(<ControlledEn />)
Without TriggerContext
Dropdown uses the popover API, so you can use Dropdown without Dropdown.Trigger.
You must then add popovertarget={id} to Dropdown, and id to Dropdown.
React
Unable to parse html
const WithoutTrigger = () => { return ( <> <Button popovertarget='dropdown'>Dropdown</Button> <Dropdown id='dropdown'> <Dropdown.List> <Dropdown.Item> <Dropdown.Button>Item</Dropdown.Button> </Dropdown.Item> </Dropdown.List> </Dropdown> </> ); }; render(<WithoutTrigger />)
HTML
You can use the native popover API directly in HTML. This can be used without JavaScript, if you don't want to polyfill.
Note that the element with popover="manual" uses two classes, ds-popover and ds-dropdown.
You choose whether you want to use popover="manual" or just popover to open the dropdown.
CSS variables and data attributes
| Name | Value |
|---|---|
| --dsc-dropdown-padding | var(--ds-size-3) var(--ds-size-2) |
| --dsc-dropdown-item-padding | var(--ds-size-2) var(--ds-size-4) |
| --dsc-dropdown-item-size | var(--ds-size-12) |
| --dsc-dropdown-background | var(--ds-color-neutral-surface-default) |
| --dsc-dropdown-border-width | var(--ds-border-width-default) |
| --dsc-dropdown-border-style | solid |
| --dsc-dropdown-border-color | var(--ds-color-neutral-border-subtle) |
| --dsc-popover-arrow-size | var(--ds-size-2) |
No relevant data attributes found.
References
We use ul and li tags in the dropdown, the choice is based on these:
- https://www.w3.org/WAI/tutorials/menus/flyout/#flyoutnavkbbtn
- https://www.w3.org/WAI/ARIA/apg/patterns/menu-button