The page navigation is complete. You may now navigate the page content as you wish.
Skip to main content

Displays a list of actions or options revealed by a toggle button. Identifiable by the chevron icon in the button.

A dropdown is a flexible component that displays a list of actions or options to the user. It should not to be confused with Select, which is used in forms as a way for the user to make a selection from a list.

Usage

When to use

  • To display a list of actions or links under a single button toggle.
  • To allow singular or multiple selection outside of a form, such as within filtering.
  • To provide the user with a way to easily switch context within the application.

When not to use

  • In forms when providing the user with options to choose from, consider Select.

Toggle

Types

Toggles come in two variant types: button and icon.

Size

ToggleButtons come in two sizes: small and medium. This allows for placement in ButtonSets with buttons of the same size.

ToggleIcons come in two sizes: small and medium.

While we provide a small size variant, we recommend only using this for the Overflow menu within Tables because the icons and images start to become unrecognizable in smaller sizes.

Chevron usage

Open Toggles use icon chevron-up, while closed Toggles use chevron-down.

ToggleButtons require a visible chevron to indicate interactivity and provide distinction between Dropdowns and standard Buttons.

Example of open and closed dropdowns

We strongly recommend providing visible chevrons on most instances of ToggleIcons to indicate interactivity. That said, it’s common to see ToggleIcons that use the more-horizontal icon without chevrons. Their placement, usually in the last column of a Table, is typically indicative of this type of interaction.

Example of open and closed dropdowns

List

Placement

Lists can be positioned to the left or right of the Toggle, and above or below the Toggle to fit more appropriately within the UI. Lists do not currently have collision detection.

Dropdown list placement examples

Size

Default width

Lists have a minimum width of 200px and a maximum width of 400px. This means if there’s a long string in a ListItem the List will automatically expand up to 400px to accommodate that content before the content wraps.

  • Signed in as
  • name@email.com

Fixed width

If you do not want the width of the List to expand automatically to accommodate the widest list item, you can indicate a specific width. As a best practice, we have set the maximum width to 400px.

  • Consul version v1.10.6
  • Import to Terraform
  • Copy and run this command in Terraform to import and manage this resource via our Terraform Provider

Height

The height of the ListContainer is automatically determined based on the contents, but the height can also be set manually. We recommend setting the height manually if you know the list will be long.

  • Integrate with Terraform Cloud
  • Create a new run task in Terraform using the URL and key below.
  • Endpoint URL
  • HMAC Key
  • Manage

ListItem

Types

Dropdown ListItem types

A note on Loading

Users may not understand why something is taking additional time to load. If possible, determine what should be displayed prior to the user opening the dropdown (e.g., on page load). If that is not possible, provide an informative loading message.

Icon usage

Icons in ListItems are optional, and we recommend letting the text speak for itself unless an icon provides additional value.

We don’t recommend mixing and matching icon use; that’s to say, if using an icon in one ListItem, use an icon in all ListItems. Doing so keeps the text aligned so the eye can scan the list of options more easily.

Do
  • About
Don’t
  • About

Critical ListItems

Icons in Critical ListItems

While icons are optional, we recommend using a relevant icon for Critical ListItems. Using the correct icon provides a stronger and more immediate visual indication that the action is destructive. Read more about how color blind users see critical actions in our UIs.

Critical action patterns

We recommend adding a second confirmation layer after the user clicks “Delete” (e.g., showing a confirmation Modal that requires the user to type “Delete” into a field before proceeding). This safeguards against accidental clicks by requiring users to confirm the destructive action.

Do

example of how to use a second confirmation layer

Don’t

example of how not to use a second confirmation layer

Content

There is no character limit for ListItems, but we recommend keeping them short and concise (~36 characters).

Take care to use dropdowns correctly. A crowded or overly complex dropdown can lead to a frustrating user experience, especially for assistive technology users. Contact the Design Systems Team to discuss alternative options if a dropdown feels too complex.

How to use this component

To make the invocation more flexible and intuitive, we provide contextual components for Toggles, ListItems, Header and Footer. For example, <Hds::Dropdown::ListItem::Separator /> would be contextually expressed as <dd.Separator />.

<Hds::Dropdown as |dd|>
  <dd.ToggleButton @text="Menu" />
  <dd.Title @text="Title Text" />
  <dd.Description @text="Descriptive text goes here." />
  <dd.Interactive @href="#" @text="Add" />
  <dd.Interactive @href="#" @text="Add More" />
  <dd.Interactive @href="#" @text="Add Another Thing Too" />
  <dd.Separator />
  <dd.Interactive @route="components" @icon="trash" @text="Delete" @color="critical" />
</Hds::Dropdown>

List position

By default, the list is positioned below the button, aligned to the right. To change the list position pass bottom-left, top-left, or top-right to @listPosition on the Dropdown component.

<Hds::Dropdown @listPosition="bottom-left" as |dd|>
  <dd.ToggleButton @text="Text Toggle" />
  <dd.Interactive @route="components" @text="Item One" />
  <dd.Interactive @route="components" @text="Item Two" />
  <dd.Interactive @route="components" @text="Item Three" />
  <dd.Interactive @text="Item Four (closes on click)" {{on "click" dd.close}} />
  <dd.Separator />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

In contexts where the Dropdown needs to be inline, to inherit the alignment from a parent, you can use the @isInline argument (and set the @listPosition accordingly to your needs):

<div class="doc-dropdown-mock-text-align-right">
  <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
    <dd.ToggleButton @text="Text Toggle" @color="secondary" />
    <dd.Interactive @route="components" @text="Item One" />
    <dd.Interactive @route="components" @text="Item Two" />
    <dd.Interactive @route="components" @text="Item Three" />
  </Hds::Dropdown>
</div>

ToggleButton

The basic invocation of ToggleButton requires @text to be passed. By default, it renders a primary button with a chevron icon.

<Hds::Dropdown as |dd|>
  <dd.ToggleButton @text="Text Toggle" />
  <dd.Interactive @route="components" @text="Item One" />
  <dd.Interactive @route="components" @text="Item Two" />
  <dd.Interactive @route="components" @text="Item Three" />
  <dd.Interactive @text="Item Four (closes on click)" {{on "click" dd.close}} />
  <dd.Separator />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

Alternatively, pass secondary to @color to display a secondary button with a chevron icon.

<Hds::Dropdown as |dd|>
  <dd.ToggleButton @text="Text Toggle" @color="secondary" />
  <dd.Interactive @route="components" @text="Item One" />
  <dd.Interactive @route="components" @text="Item Two" />
  <dd.Interactive @route="components" @text="Item Three" />
  <dd.Interactive @text="Item Four (closes on click)" {{on "click" dd.close}} />
  <dd.Separator />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

ToggleIcon

ToggleIcon as overflow menu

Overflow menus are often found in the last column of a Tables. This is the only use case where it is acceptable to use @hasChevron=false. @text is still required, because it supplies the aria-label for ToggleIcon.

<Hds::Dropdown as |dd|>
  <dd.ToggleIcon @icon="more-horizontal" @text="Overflow Options" @hasChevron={{false}} />
  <dd.Interactive @route="components" @text="Create" />
  <dd.Interactive @route="components" @text="Read" />
  <dd.Interactive @route="components" @text="Update" />
  <dd.Separator />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

ToggleIcon as user menu

@text is still required, because it supplies the aria-label for ToggleIcon.

<Hds::Dropdown as |dd|>
  <dd.ToggleIcon @icon="user" @text="user menu" />
  <dd.Title @text="Signed In" />
  <dd.Description @text="email@domain.com" />
  <dd.Separator />
  <dd.Interactive @route="components" @text="Settings and Preferences" />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

ToggleIcon with other icons

Pass any icon name to @icon to change the icon used in ToggleIcon. @text is still required, because it supplies the aria-label for ToggleIcon.

<Hds::Dropdown as |dd|>
  <dd.ToggleIcon @icon="settings" @text="settings menu" />
  <dd.Title @text="Signed In" />
  <dd.Description @text="email@domain.com" />
  <dd.Separator />
  <dd.Interactive @route="components" @text="Settings and Preferences" />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

ListItem::Interactive

ListItem::Interactive renders the correct element based on the passing of an @route, @href, or the addition of a click event (e.g., {{on "click" this.myAction}}). Internally, the component uses the Hds::Interactive utility component.

Rendering a button

If you add an event handler (no @href or @route), a <button> element will be rendered:

{{!-- The Doc::ListContainer component is just to help the component render properly --}}
<Doc::ListContainer class="hds-dropdown__list">
  <Hds::Dropdown::ListItem::Interactive {{on "click" this.myAction}} @text="Run command" />
</Doc::ListContainer>

Internal Link?

When using the @href argument, you’re indicating an external link (instead of a route). So, a few relevant HTML attributes are added—target="_blank" and rel="noopener noreferrer". However, if the @href really does point to an internal link or uses a different protocol (e.g., mailto or ftp), pass @isHrefExternal=false to the component and it will not add any extra HTML attributes.

If you pass an @href argument, a link (<a> element) will be generated:

{{!-- The Doc::ListContainer component is just to help the component render properly --}}
<Doc::ListContainer class="hds-dropdown__list">
  <Hds::Dropdown::ListItem::Interactive @href="https://www.hashicorp.com/request-demo/terraform" @text="Request a demo" />
</Doc::ListContainer>

Rendering a LinkTo (with @route)

Pass a @route to render Ember <LinkTo>. If the route is external to your current engine, pass @isRouteExternal=true to use <LinkToExternal> instead of <LinkTo>. For more details see the Hds::Interactive component documentation. All the standard arguments for the <LinkTo/LinkToExternal> components are supported (e.g., models/model/query/current-when/replace).

{{!-- The Doc::ListContainer component is just to help the component render properly --}}
<Doc::ListContainer class="hds-dropdown__list">
  <Hds::Dropdown::ListItem::Interactive @route="my.page.route" @model="my.page.model" @text="Activate cluster" />
</Doc::ListContainer>

With a loading “interactive” item

There may be use cases when it’s necessary to put an item in a “loading” state while the app performs some operations (e.g., asynchronously checking the user’s permissions to execute a certain operation once the Toggle’s been clicked).

Pass the argument @isLoading=true to the item. This will show a “loading” icon (even if an argument @icon is provided) and sets the item as non-interactive until the value of @isLoading is set to false again.

<Hds::Dropdown as |dd|>
  <dd.ToggleIcon @icon="more-horizontal" @text="Overflow Options" @hasChevron={{false}} />
  <dd.Interactive @route="components" @isLoading={{true}} @text="Edit cluster" @color="action" @icon="edit" />
  <dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>

ListItem::Generic

When using the “generic” ListItem, the product team is responsible for implementing the layout and accessibility.

ListItem::Generic allows you to pass custom elements to the Dropdown.

<Hds::Dropdown as |dd|>
  <dd.ToggleButton @text="Text Toggle" @color="secondary" />
  <dd.Title @text="Integrate with Terraform Cloud" />
  <dd.Description @text="Create a new run task in Terraform using the URL and key below." />
  <dd.Generic>
    <Hds::Link::Standalone @text="Watch tutorial video" @icon="film" @href="/" />
  </dd.Generic>
  <dd.CopyItem @text="https://api.cloud.hashicorp.com" @copyItemTitle="Endpoint URL" />
  <dd.CopyItem @text="91ee1e8ef65b337f0e70d793f456c71d" @copyItemTitle="HMAC Key" />
</Hds::Dropdown>

Component API

The Dropdown component is composed of different child components each with their own APIs:

  • The Dropdown component
    • Optional header and footer
  • Toggle components to open/close the Dropdown
    • ToggleButton
    • ToggleIcon
  • ListItem components, to build the Dropdown’s list items
    • Description
    • Generic
    • Interactive
    • Separator
    • Title

Name
listPosition
Type
string
Values
  • bottom-left
  • bottom-right (default)
  • top-left
  • top-right
Name
width
Type
string
Values
any valid CSS width (px, rem, etc)
Description
By default, the Dropdown List has a min-width of 200px and a max-width of 400px, so it adapts to the content size. If a @width parameter is provided then the list will have a fixed width.
Name
height
Type
string
Values
any valid CSS width (px, rem, etc)
Description
If a @height parameter is provided then the list will have a fixed height.
Name
isInline
Type
boolean
Default
  • false (default)
Description
If a @isInline parameter is provided then the element will be displayed as inline-block (useful to achieve specific layouts like in a container with right alignment). Otherwise it will be have a block layout.
Name
close
Type
function
Description
Function to programmatically close the Dropdown.

If this function is invoked using an {{on "click"}} modifier applied to the ListItem::Interactive element, there is a quirky behavior of the Ember <LinkTo> component which requires a workaround to have the events executed in the right order (this happens only if it has a @route argument). Read more about the issue and a possible solution in this GitHub comment.
Name
onClose
Type
function
Description
Callback function invoked when the Dropdown is closed, if provided.
Name
…attributes
Description
This component supports use of ...attributes.

If the Dropdown content exceeds the height of the container, the header and footer remain fixed while the list of items adjusts its height.

Name
yield
Description
Elements nested in this child component are yielded inside the Dropdown header/footer.
Name
hasDivider
Type
boolean
Default
  • false (default)
Name
…attributes
Description
This component supports use of ...attributes.

Toggle::Button

Name
text
Type
string
Required
Required
Description
Text of the ToggleButton. If no text value is defined, an error will be thrown.
Name
color
Type
enum
Values
  • primary (default)
  • secondary
Name
size
Type
enum
Values
  • medium (default)
  • small
Name
icon
Type
string
Description
Acceptable value: any icon name.
Name
count
Type
string
Description
Displays an optional count indicator using the Badge Count component.
Name
badge
Type
string
Description
Displays an optional badge indicator using the Badge component.
Name
badgeIcon
Type
string
Description
Appends an icon to the optional badge indicator. Acceptable value: any icon name.
Name
…attributes
Description
This component supports use of ...attributes.

Toggle::Icon

Name
text
Type
string
Required
Required
Description
Value of aria-label for the ToggleIcon. If no text value is defined, an error will be thrown.
Name
icon
Type
string
Description
Acceptable value: any icon name.
Name
hasChevron
Type
boolean
Default
  • true (default)
Description
Per design, false is only currently allowed when the "more-horizontal" icon is used; it is set to true by default.
Name
imageSrc
Type
string
Name
…attributes
Description
This component supports use of ...attributes.

ListItem::Interactive

Name
text
Type
string
Required
Required
Description
Text to be used in the item. If no text value is defined, an error will be thrown.
Name
color
Type
enum
Values
  • action (default)
  • critical
Description
Acceptable values: “action” or “critical”.
Name
icon
Type
string
Description
Acceptable value: any icon name.
Name
isLoading
Type
boolean
Default
  • false (default)
Description
Controls if the item is in “loading” state. When in this state, the item is not actually interactive, but you can pass the other expected arguments for the item (they’re simply ignored).
Name
href
Description
URL passed to the <a> element.
Name
isHrefExternal
Type
boolean
Default
  • false (default)
Description
Indicates whether or not the <a> link is external, in which case target="_blank" and rel="noopener noreferrer" attributes are added automatically.
Name
route/models/model/query/current-when/replace
Description
Parameters passed as arguments to the <LinkTo/LinkToExternal> component.
Name
isRouteExternal
Type
boolean
Default
  • false (default)
Description
Controls if the “LinkTo” is external to the Ember engine (more details here) in which case it will use a <LinkToExternal> instead of a simple <LinkTo> for the @route.
Name
…attributes
Description
This component supports use of ...attributes.

In this component, the ...attributes are not supported on the root element (an <li> element) but on the underlying element/component (<button>, <a>, <LinkTo> or <LinkToExternal> depending on the @route/@href arguments).

ListItem::Title

Name
text
Type
string
Required
Required
Description
Text to be used for the title. If no text value is defined, an error will be thrown.
Name
…attributes
Description
This component supports use of ...attributes.

ListItem::Description

Name
text
Type
string
Required
Required
Description
Text to be used for the description. If no text value is defined, an error will be thrown.
Name
…attributes
Description
This component supports use of ...attributes.

ListItem::Separator

Name
…attributes
Description
This component supports use of ...attributes.

ListItem::CopyItem

Name
copyItemTitle
Type
string
Name
text
Type
string
Required
Required
Description
Text to be copied. If no text value is defined, an error will be thrown.

ListItem::Checkmark

Name
yield
Description
Content to be used in the item.
Name
selected
Type
boolean
Default
  • false (default)
Description
Displays a checkmark symbol indicating the current selection.
Name
icon
Type
string
Description
Acceptable value: any icon name.
Name
count
Type
string
Description
Displays an optional count indicator.
Name
href
Description
URL passed to the <a> element.
Name
isHrefExternal
Type
boolean
Default
  • false (default)
Description
Indicates whether or not the <a> link is external, in which case target="_blank" and rel="noopener noreferrer" attributes are added automatically.
Name
route/models/model/query/current-when/replace
Description
Parameters passed as arguments to the <LinkTo/LinkToExternal> component.
Name
isRouteExternal
Type
boolean
Default
  • false (default)
Description
Controls if the “LinkTo” is external to the Ember engine (more details here) in which case it will use a <LinkToExternal> instead of a simple <LinkTo> for the @route.
Name
…attributes
Description
This component supports use of ...attributes.

In this component, the ...attributes are not supported on the root element (an <li> element) but on the underlying element/component (<button>, <a>, <LinkTo> or <LinkToExternal> depending on the @route/@href arguments).

ListItem::Checkbox

Name
yield
Description
Content to be used in the item as label for the input control.
Name
value
Type
string
Description
Input control’s value attribute.
Name
icon
Type
string
Description
Acceptable value: any icon name.
Name
count
Type
string
Description
Displays an optional count indicator.
Name
id
Type
string
Description
Input control’s id attribute.

By default, the id is automatically generated by the component. Use this argument to pass a custom id.
Name
…attributes
Description
This component supports use of ...attributes.

The attributes will be applied to the <input> element. This means you can use all the standard HTML attributes of the <input> element and all the usual Ember techniques for event handling, validation, etc.

Examples of HTML attributes: id, name, value, placeholder, disabled, readonly, required. See the whole list of HTML attributes. Examples of Ember modifiers: {{on "input" [do something]}}, {{on "change" [do something]}}, {{on "blur" [do something]}}.

ListItem::Radio

Name
yield
Description
Content to be used in the item as label for the input control.
Name
value
Type
string
Description
Input control’s value attribute.
Name
icon
Type
string
Description
Acceptable value: any icon name.
Name
count
Type
string
Description
Displays an optional count indicator.
Name
id
Type
string
Description
Input control’s id attribute.

By default, the id is automatically generated by the component. Use this argument to pass a custom id.
Name
…attributes
Description
This component supports use of ...attributes.

The attributes will be applied to the <input> element. This means you can use all the standard HTML attributes of the <input> element and all the usual Ember techniques for event handling, validation, etc.

Examples of HTML attributes: id, name, value, placeholder, disabled, readonly, required. See the whole list of HTML attributes. Examples of Ember modifiers: {{on "input" [do something]}}, {{on "change" [do something]}}, {{on "blur" [do something]}}.

ListItem::Generic

Name
yield
Description
Elements nested in this child component are yielded inside the ListItem. When using the “generic” ListItem, the product team is responsible for implementing the layout and accessibility.
Name
…attributes
Description
This component supports use of ...attributes.

Anatomy

Dropdown anatomy

Element Usage
Toggle Required
Header Optional
List Required
Footer Optional

Toggle

Toggle button anatomy Toggle icon anatomy

Element Usage
Text, Icon, or Avatar One is required
Chevron Required, except on the Overflow toggle
Container Required

ListItem

Dropdown ListItem anatomy

Element Usage
Text Required
Icon Required for Critical ListItems; Optional otherwise
Indicator Visible in hover and active state
Focus ring Visible in focus state

States

A note on disabled states

Because disabled states completely remove the interactive function of an element, it can be challenging for a user to understand why it has been disabled and/or why they cannot interact with that element. In an effort to avoid this confusion, we opt for using methods like enabling or hiding the element and, thus, are not offering disabled states for the Dropdown. Read more about when to enable vs hide.

Toggle

Example of dropdown toggle states

ListItem

Interactive

Example of listitem interactive states

Checkbox

Example of listitem checkbox states

Checkmark

Example of listitem checkmark states

Radio

Example of listitem radio states

Conformance Rating

Conditionally conformant

This component is conditionally conformant.

  1. When truncation occurs, a keyboard-only user cannot access the truncated content.
  2. The component is no longer conformant if the chevron icon is removed from the ToggleButton.

Known issues

ToggleIcon with no chevron

Setting @hasChevron to false on ToggleIcons doesn’t provide enough affordance; it’s not quickly seen as actionable.

Color blind users and critical actions

Color blind users, specifically those with Achromatopsia, may have a hard time perceiving Critical ListItems within our Dropdown component.

To provide a more accessible experience, we recommend:

  • Using strong, clear language for the text (e.g., “Delete…”, “Revoke…”, etc.).
  • Adding a relevant icon that indicates the action is destructive (e.g., trash).
  • Moving the Critical ListItem to the bottom of the list or the section.
    • If at the bottom of a list, consider adding a separator above the Critical ListItem to help separate it from other ListItems.
  • Adding a second confirmation layer after the user clicks “Delete” (e.g., showing a confirmation Modal that requires the user to type “Delete” into a field before proceeding).

Keyboard navigation

Example of the focus order for a Dropdown

Applicable WCAG Success Criteria

This section is for reference only. This component intends to conform to the following WCAG Success Criteria:

  • 1.3.1 Info and Relationships (Level A):
    Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
  • 1.3.2 Meaningful Sequence (Level A):
    When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined.
  • 1.4.1 Use of Color (Level A):
    Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.
  • 1.4.10 Reflow (Level AA):
    Content can be presented without loss of information or functionality, and without requiring scrolling in two dimensions.
  • 1.4.11 Non-text Contrast (Level AA):
    The visual presentation of the following have a contrast ratio of at least 3:1 against adjacent color(s): user interface components; graphical objects.
  • 1.4.12 Text Spacing (Level AA):
    No loss of content or functionality occurs by setting all of the following and by changing no other style property: line height set to 1.5; spacing following paragraphs set to at least 2x the font size; letter-spacing set at least 0.12x of the font size, word spacing set to at least 0.16 times the font size.
  • 1.4.3 Minimum Contrast (Level AA):
    The visual presentation of text and images of text has a contrast ratio of at least 4.5:1
  • 1.4.4 Resize Text (Level AA):
    Except for captions and images of text, text can be resized without assistive technology up to 200 percent without loss of content or functionality.
  • 2.1.1 Keyboard (Level A):
    All functionality of the content is operable through a keyboard interface.
  • 2.1.2 No Keyboard Trap (Level A):
    If keyboard focus can be moved to a component of the page using a keyboard interface, then focus can be moved away from that component using only a keyboard interface.
  • 2.4.3 Focus Order (Level A):
    If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability.
  • 2.4.7 Focus Visible (Level AA):
    Any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible.


Support

If any accessibility issues have been found within this component, let us know by submitting an issue.