A dropdown is a flexible component that displays a list of actions or options to the user. It should not 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.
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.
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.
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.
Size
Width
By default, 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 the content before it wraps.
- Signed in as
- name@email.com
If you do not want the width of the List to expand automatically to accommodate the widest ListItem, you can indicate a specific width between 200px–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
-
Docs: Import usage
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. In code, the @height
property actually acts as a max-height
.
Header
A Header provides a fixed space at the top of the List. Typically, Headers house a search feature that allows the user to search/filter through the available options in the list. This is great for really long lists when filtering on complex datasets.
Footer
A Footer provides a fixed space at the bottom of the List. Typically, Footers house actions related to the ListItems, e.g., when found in a filtering pattern an "Apply" Button can be used to submit the selections.
ListItem
Types
For maximum flexibility, we offer a variety of ListItems options.
Interactive ListItems
Use Interactive ListItems for actions (buttons) or links.
- Use
Interactive - Critical
for destructive actions. - Use
Interactive - Action
for everything else.
Selection ListItems
Selection ListItems allow the user to select one or more options within a Dropdown.
- Use
Checkmark
for switching context, e.g., organization switchers, project switchers, etc. Use for single selection only, as it doesn't provide enough indication that multi-selection is possible. For multi-selection, useCheckbox
. - Use
Checkbox
for multi-selection within a form or larger filter pattern. - Use
Radio
for single selection within a form or larger filter pattern.
Use Checkmark
for context switching.
Don't use Checkmark
instead of Radio
in larger filter patterns.
Non-interactive
Non-interactive ListItems help provide structure and context to a Dropdown. Types include: Description
, Loading
, Separator
, and Title
.
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.
Generic
The Generic ListItem allows you to add custom content in place of a ListItem. It includes predefined left and right padding to ensure proper alignment with other ListItems in the List.
Icon usage
Icons in ListItems are optional. Generally, we recommend letting the text speak for itself, but icons can add value in the following situations:
- When they reinforce the content, e.g.,
edit
for an edit or rename action. - When using Critical ListItems; read more about how color blind users see critical actions in our UIs.
- To avoid inconsistent icon use within the same List. Instead use icons in all ListItems. Doing so keeps the text aligned so the eye can scan the list of options more easily.
Use icons consistently and when they reinforce the content.
Avoid inconsistent icon use.
Content
While there are no character limits for ListItems, we recommend keeping them short and concise so the List is easy to scan.
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 take another action before proceeding). This safeguards against accidental clicks by requiring users to confirm the destructive action.
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>
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)" />
<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)" />
<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= />
<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>
List placement
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)" />
<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= @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>
List size
You can explicitly control the height or width of a list. Any acceptable value (px, rem, em) can be declared:
<Hds::Dropdown @isInline= @height="170px" @width="250px" 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 @route="components" @text="Item Four" />
<dd.Interactive @route="components" @text="Item Five" />
<dd.Interactive @route="components" @text="Item Six" />
<dd.Interactive @route="components" @text="Item Seven" />
</Hds::Dropdown>
List footer
It is possible that you may want to add a list footer for things like a set of buttons for a filter control:
<Hds::Dropdown @height="284px" as |dd|>
<dd.ToggleButton @icon="tag" @text="Tags" @color="secondary" />
<dd.Checkbox>access</dd.Checkbox>
<dd.Checkbox>homework</dd.Checkbox>
<dd.Checkbox>discovery</dd.Checkbox>
<dd.Checkbox>memories</dd.Checkbox>
<dd.Checkbox>music</dd.Checkbox>
<dd.Checkbox>pharell</dd.Checkbox>
<dd.Checkbox>punk</dd.Checkbox>
<dd.Checkbox>random</dd.Checkbox>
<dd.Checkbox>robots</dd.Checkbox>
<dd.Checkbox>tag</dd.Checkbox>
<dd.Footer @hasDivider=>
<Hds::ButtonSet>
<Hds::Button @text="Apply filters" @isFullWidth= @size="small" />
<Hds::Button @text="Cancel" @color="secondary" @size="small" />
</Hds::ButtonSet>
</dd.Footer>
</Hds::Dropdown>
ListItem::Interactive
ListItem::Interactive
renders the correct element based on the passing of a @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:
<Doc::ListContainer class="hds-dropdown__list">
<Hds::Dropdown::ListItem::Interactive @text="Run command" />
</Doc::ListContainer>
Rendering a link with @href
If you pass an @href
argument, a link (<a>
element) will be generated:
<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
).
<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= />
<dd.Interactive @route="components" @isLoading= @text="Edit cluster" @color="action" @icon="edit" />
<dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>
ListItem::CopyItem
To enable users to copy a snippet of code (eg. URLs, secrets, code blocks, etc.).
Using the @isTruncated
argument it is possible to constrain the text to one-line and truncate it if it does not fit the available space. Care should be taken in choosing to use this feature as there are accessibility concerns.
<Hds::Dropdown as |dd|>
<dd.ToggleButton @listPosition="bottom-left" @text="Create run task" @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.CopyItem @text="https://api.cloud.hashicorp.com" @copyItemTitle="Endpoint URL" />
<dd.CopyItem @isTruncated= @text="91ee1e8ef65b337f0e70d793f456c71d91ee1e8ef65b337f0e70d793f456c71d" @copyItemTitle="HMAC Key" />
</Hds::Dropdown>
ListItem::Checkmark
For switching context (e.g., organization switchers, project switchers, etc.) use ListItem::Checkmark
.
<Hds::Dropdown @listPosition="bottom-left" as |dd|>
<dd.ToggleButton @text="HCP Design Sandbox" @color="secondary" />
<dd.Checkmark>ACME Org</dd.Checkmark>
<dd.Checkmark @selected=>HCP Design Sandbox</dd.Checkmark>
<dd.Footer @hasDivider=>
<Hds::Link::Standalone @icon="list" @text="All Organizations" @color="secondary" @href="#" />
</dd.Footer>
</Hds::Dropdown>
ListItem::Checkbox
For multi-selection within a form or larger filter pattern use ListItem::Checkbox
.
<Hds::Dropdown @listPosition="bottom-left" as |dd|>
<dd.ToggleButton @count="2" @text="Status" @color="secondary" />
<dd.Checkbox @count="4">Failing</dd.Checkbox>
<dd.Checkbox @count="2" checked>Active</dd.Checkbox>
<dd.Checkbox @count="1">Starting</dd.Checkbox>
<dd.Checkbox @count="3" checked>Pending</dd.Checkbox>
<dd.Footer @hasDivider=>
<Hds::Button @text="Apply filters" @isFullWidth= @size="small" />
</dd.Footer>
</Hds::Dropdown>
ListItem::Radio
For single selection within a form or larger filter pattern use ListItem::Radio
.
<Hds::Dropdown @listPosition="bottom-left" as |dd|>
<dd.ToggleButton @text="Status" @color="secondary" />
<dd.Radio name="status" @count="4">Failing</dd.Radio>
<dd.Radio name="status" @count="2" checked>Active</dd.Radio>
<dd.Radio name="status" @count="1">Starting</dd.Radio>
<dd.Radio name="status" @count="3">Pending</dd.Radio>
<dd.Footer @hasDivider=>
<Hds::Button @text="Apply filters" @isFullWidth= @size="small" />
</dd.Footer>
</Hds::Dropdown>
ListItem::Generic
ListItem::Generic
allows you to pass custom elements to the Dropdown.
<Hds::Dropdown @listPosition="bottom-left" 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>
</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
Dropdown
listPosition
string
- bottom-left
- bottom-right (default)
- top-left
- top-right
width
string
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.
height
string
@height
parameter is provided then the list will have a max-height.
isInline
boolean
- false (default)
@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.
close
function
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.
onClose
function
…attributes
...attributes
.
Dropdown::Header and Dropdown::Footer
If the Dropdown content exceeds the height of the container, the header and footer remain fixed while the list of items adjusts its height.
yield
hasDivider
boolean
- false (default)
…attributes
...attributes
.
Toggle::Button
text
string
required
color
enum
- primary (default)
- secondary
size
enum
- medium (default)
- small
icon
string
count
string
badge
string
badgeIcon
string
…attributes
...attributes
.
Toggle::Icon
text
string
required
aria-label
for the ToggleIcon. If no text value is defined, an error will be thrown.
icon
string
hasChevron
boolean
- true (default)
false
is only currently allowed when the "more-horizontal" icon is used; it is set to true
by default.
imageSrc
string
…attributes
...attributes
.
ListItem::Interactive
text
string
required
color
enum
- action (default)
- critical
icon
string
isLoading
boolean
- false (default)
href
<a>
element.
isHrefExternal
boolean
- false (default)
<a>
link is external, in which case target="_blank"
and rel="noopener noreferrer"
attributes are added automatically.
route/models/model/query/current-when/replace
<LinkTo/LinkToExternal>
component.
isRouteExternal
boolean
- false (default)
<LinkToExternal>
instead of a simple <LinkTo>
for the @route.
…attributes
...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
text
string
required
…attributes
...attributes
.
ListItem::Description
text
string
required
…attributes
...attributes
.
ListItem::Separator
…attributes
...attributes
.
ListItem::CopyItem
copyItemTitle
string
text
string
required
Notice: this argument is forwarded (as
textToCopy
) to the Copy::Snippet
component.
isTruncated
boolean
- false (default)
There are accessibility concerns if using this feature. See the Accessibility section of the
Copy::Snippet
component for more information.
Notice: this argument is forwarded to the
Copy::Snippet
component.
ListItem::Checkmark
yield
selected
boolean
- false (default)
icon
string
count
string
href
<a>
element.
isHrefExternal
boolean
- false (default)
<a>
link is external, in which case target="_blank"
and rel="noopener noreferrer"
attributes are added automatically.
route/models/model/query/current-when/replace
<LinkTo/LinkToExternal>
component.
isRouteExternal
boolean
- false (default)
<LinkToExternal>
instead of a simple <LinkTo>
for the @route.
…attributes
...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
yield
value
string
value
attribute.
icon
string
count
string
id
string
id
attribute.
By default, the
id
is automatically generated by the component. Use this argument to pass a custom id
.
…attributes
...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
yield
value
string
value
attribute.
icon
string
count
string
id
string
id
attribute.
By default, the
id
is automatically generated by the component. Use this argument to pass a custom id
.
…attributes
...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
yield
…attributes
...attributes
.
Anatomy
Dropdown
Element | Usage |
---|---|
Toggle | Required |
Header | Optional |
List | Required |
Footer | Optional |
Toggle
Element | Usage |
---|---|
Text, Icon, or Avatar | One is required |
Chevron | Required, except on the Overflow toggle |
Container | Required |
ListItem
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
Toggle
ListItem
Interactive
Checkbox
Checkmark
Radio
Conformance Rating
This component is conditionally conformant.
- When truncation occurs, a keyboard-only user cannot access the truncated content.
- 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
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.