The dropdown component has several flexible features that allow developers to build the dropdown menu they wish. A dropdown displays a list of links or actions to choose from. It should not to be confused with a select element which is used in a form (element) as a way for the user to select one or more options from a list.
The Dropdown
component is composed of different child components, each with their own APIs:
the dropdown component (parent to the child components)
Toggle components to open/close the dropdown
- ToggleButton
- ToggleIcon
And finally, list item components, to build the dropdown's list items
- Description
- Generic
- Interactive
- Separator
- Title
Notice: to make the invocation more intuitive for developers, all the sub-components are named yields, so the yielded name is a simplified version of the full component name (eg. Hds::ListItem::Interactive
becomes just Interactive
). See below how they are invoked as yielded components.
Dropdown
Here is the API for the main ("container") component:
- Name
-
listPosition
- Type
-
string
- Values
-
- left
- right (default)
- Name
-
width
- Type
-
string
- Values
- any valid CSS width (px, rem, etc)
- Description
-
Notice: by default the dropdown list has a
min-width
of200px
and amax-width
of400px
applied to it, so it adapts to the content size. If a@width
parameter is provided then the list will have a fixed width.
- Name
-
close
- Type
-
function
- Description
-
Function that can be called to programmatically close the dropdown. Notice: if this function is invoked using an
{{on "click"}}
modifier applied to theListItem::Interactive
element, there is a quirk behaviour of the Ember<LinkTo>
component that will require some workaround to have the events executed in the right order (this happens only if it has a@route
argument). Jamie White has detailed 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
-
...attributes
spreading is supported on this component.
Toggle::Button
Here is the API for the "button-like" toggle component (yielded in a hash under the key ToggleButton
):
- Name
-
text
- Type
-
string
- Required
-
Required
- Description
- The text of the toggle button. 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
-
…attributes
- Description
-
...attributes
spreading is supported on this component.
Toggle::Icon
Here is the API for the icon-only toggle component (yielded as ToggleIcon
):
- Name
-
text
- Type
-
string
- Required
-
Required
- Description
- The value of aria-label for the toggle icon. If no text value is defined an error will be thrown.
- Name
-
icon
- Type
-
string
- Description
- Acceptable value: any Flight icon name.
- Name
-
hasChevron
- Type
-
boolean
- Description
-
Per design,
false
is only acceptable when the "more-horizontal" icon is used; as such, it is set totrue
by default.
- Name
-
imageSrc
- Type
-
string
- Name
-
…attributes
- Description
-
...attributes
spreading is supported on this component.
ListItem::CopyItem
- Name
-
copyItemTitle
- Type
-
string
- Name
-
text
- Type
-
string
- Required
-
Required
- Description
- The text to be copied. If no text value is defined an error will be thrown.
ListItem::Description
Here is the API for the "description" list item component (yielded in a hash under the key Description
):
- Name
-
text
- Type
-
string
- Required
-
Required
- Description
- The text to be used for the description. If no text value is defined an error will be thrown.
- Name
-
…attributes
- Description
-
...attributes
spreading is supported on this component.
ListItem::Generic
Here is the API for the "generic" list item component (yielded in a hash under the key Generic
):
- Name
-
yield
- Description
- Elements passed as children of this sub-component are yielded inside the list item. Notice: when using the "generic" list item the developer is completely responsible for any element yielded, including the accessibility of that element, as well as the layout of the content (we provide only the horizontal padding for consistency with the other items).
- Name
-
…attributes
- Description
-
...attributes
spreading is supported on this component.
ListItem::Interactive
Here is the API for the "interactive" list item component (yielded in a hash under the key Interactive
):
- Name
-
text
- Type
-
string
- Required
-
Required
- Description
- The 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
- Acceptabe values:
- Name
-
icon
- Type
-
string
- Description
- Acceptable value: any Flight icon name.
- Name
-
isLoading
- Type
-
boolean
- Description
- This controls if the item is in "loading" state. Notice: 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
-
This is the URL parameter that is passed down to the
<a>
element.
- Name
-
isHrefExternal
- Type
-
boolean
- Description
-
This controls if the
<a>
link is external and so for security reasons we need to add thetarget="_blank"
andrel="noopener noreferrer"
attributes to it.
- Name
-
route models model query current-when replace
- Description
-
These are the parameters that are passed down as arguments to the
<LinkTo/LinkToExternal>
component.
- Name
-
isRouteExternal
- Type
-
boolean
- Description
-
This 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
-
...attributes
spreading is supported on this component. Important: in this specific component, the...attributes
are not spread on the root element of the component (an<li>
element) but on the underlying element/component (<button>
,<a>
,<LinkTo>
or<LinkToExternal>
depending on the@route/@href
arguments).
ListItem::Separator
Here is the API for the "separator" list item component (yielded in a hash under the key Separator
):
- Name
-
…attributes
- Description
-
...attributes
spreading is supported on this component.
ListItem::Title
Here is the API for the "description" list item component (yielded in a hash under the key Title
):
- Name
-
text
- Type
-
string
- Required
-
Required
- Description
- The text to be used for the title. If no text value is defined an error will be thrown.
- Name
-
…attributes
- Description
-
...attributes
spreading is supported on this component.
Invocation
To make the invocation more intuitive for developers, we've provided contextual components for the toggles and list-item items. For example, <Hds::Dropdown::ListItem::Separator />
is yielded in a hash under the key <XX.Separator />
when invoked:
<Hds::Dropdown as |dd|>
<dd.ToggleButton @text="..." />
<dd.Title @text="Lorem ipsum" />
<dd.Description @text="Lorem ipsum dolor sine qua non est." />
<dd.Interactive @href="..." @text="Add" />
<dd.Separator />
<dd.Interactive @route="components" @icon="trash" @text="Delete" @color="critical" />
</Hds::Dropdown>
URLs and routes handling
The Interactive
list item renders the correct element based on the passing of an @route
, @href
, or the addition of a click event (i.e., {{on "click" this.myAction}}
).
Notice: the Interactive
list item component internally uses the generic Hds::Interactive
component. For more details about how this low-level component works please refer to its documentation page.
Basic use
If you don't pass a @href
or @route
argument a simple <button>
will be generated:
<Hds::Dropdown as |dd|>
...
<dd.Interactive @text="Run command" />
</Hds::Dropdown>
Notice: in this case you will have to add your own event handling function to it.
With @href
If you pass a @href
argument a <a>
link will be generated:
<Hds::Dropdown as |dd|>
...
<dd.Interactive @href="https://www.hashicorp.com/request-demo/terraform" @text="Request a demo" />
</Hds::Dropdown>
Important: when using the @href
argument the component adds by default the attributes target="_blank"
and rel="noopener noreferrer"
to the <a>
element (because this is the most common use case: internal links are generally handled using a @route
argument). If the href
points to an internal link, or uses a different protocol (eg. "mailto" of "ftp") you can pass @isHrefExternal=true
to the component and it will not add the target
and rel
attributes (but you can pass yours if needed, using the ...attributes
spreading. For more details see the Hds::Interactive component.
With @route
If you pass a @route
argument a <a>
link will be generated using a <LinkTo>
Ember component:
<Hds::Dropdown as |dd|>
...
<dd.Interactive @route="my.page.route" @model="my.page.model" @text="Activate cluster" />
</Hds::Dropdown>
Important: if the route is external to your current engine you have to pass also @isRouteExternal=true
to the component so that it will use <LinkToExternal>
instead of a simple <LinkTo>
for the @route
. For more details see the Hds::Interactive component
Notice: all the standard arguments for the <LinkTo/LinkToExternal>
components are supported (eg. models/model/query/current-when/replace
).
Examples
ToggleButton + ListItem, Separator
This example demonstrates the use of a dropdown with a toggle-button, links, a separator and a link (color, critical):
<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>
Rendered (positioned to the right):
ToggleButton + Title, Description, CopyItem, Separator
This example demonstrates the use of a dropdown with a toggle-button (color, secondary), title, description, a generic (which is yielding a Link::Standalone component), copy-item, a separator and a link (color, critical):
To indicate that a secondary button style should be used for the "button" toggle, add @color="secondary"
. If no @color
is declared, primary
will be used by default.
<Hds::Dropdown as |dd| >
<dd.ToggleButton @text="Integrate with Terraform Cloud" @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>
Rendered as secondary variation (positioned to the right):
Notice: when using the "generic" list item the developer is completely responsible for any element yielded, including the accessibility of that element, as well as the layout of the content (we provide only the horizontal padding for consistency with the other items).
ToggleIcon for "overflow" dropdown menus
Example: an "overflow" toggle for use only in a table element (per design). The dropdown has default and destructive (critical) links. This is the only use case where it is acceptable to use @hasChevron=false
.
Note that toggleText
is still required, because it supplies the aria-label
for the toggle button.
<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>
Rendered in a table cell:
Column A
Column B
Column C
Row 1, cell 1
Row 1, cell 2
Row 2, cell 1
Row 2, cell 2
Row 3, cell 1
Row 3, cell 2
Row 4, cell 1
Row 4, cell 2
With a loading "interactive" item
Example: there may be use cases when it's necessary to put an item in a "loading" state while the app performs some operations (eg. checking asynchronously the user's permission to execute a certain operation, once the toggle has been clicked).
In that case the argument @isLoading=true
can be passed to the item: this will show a "loading" icon (even if an argument @icon
is provided) and set 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>
Rendered in a table cell:
ID
Status
Cluster ABC
Running
Cluster XYZ
Idle
ToggleIcon as user menu
In this example, we have a user icon with a title, description, separator, and links.
Note that toggleText
is still required, because it supplies the aria-label
for the toggle button.
<Hds::Dropdown as |dd|>
<dd.ToggleIcon @icon="user" @text="user menu" />
<dd.Title @text="Signed In" />
<dd.Description @text="design-systems@hashicorp.com" />
<dd.Separator />
<dd.Interactive @route="components" @text="Settings and Preferences" />
<dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>
Rendered as a toggle/icon for a user menu (positioned to the right):
Here is a customized example to demonstrate how that would look like in dark mode (not supported by the design system yet):
ToggleIcon with other icons
In this example, we have a settings icon with a title, description, separator, and links.
Note that toggleText
is still required, because it supplies the aria-label
for the toggle button.
<Hds::Dropdown as |dd|>
<dd.ToggleIcon @icon="settings" @text="settings menu" />
<dd.Title @text="Signed In" />
<dd.Description @text="design-systems@hashicorp.com" />
<dd.Separator />
<dd.Interactive @route="components" @text="Settings and Preferences" />
<dd.Interactive @route="components" @text="Delete" @color="critical" @icon="trash" />
</Hds::Dropdown>
Rendered (positioned to the right):
Toggles
Toggle::Button
Toggle::Icon
States
List Items
Title / Description / Separator
- A simple title
- A description.
-
Item
- A longer title that could span multiple lines if the characters surpass a certain length
- A longer description that could span on multiple lines if the number of characters require more width than the dropdown provides by default.
-
A longer item that could span multiple lines if the characters surpass a certain length
- A longer title that could span multiple lines if the characters surpass a certain length
- A longer description that could span on multiple lines if the number of characters require more width than the dropdown provides by default.
-
A longer item that could span multiple lines if the characters surpass a certain length
Interactive
Generated element
<button>
Colors
States (in each color)
Generic
-
some generic content here
CopyItem
Content
-
Lorem ipsum dolor
States
When to use
- To display a list of actions under a single button toggle.
When not to use
- In forms, when needing to select one or more options, use a Select
- When selecting an option results in immediate navigation or update to the page contentx, use a Context Switcher (coming soon)
Dropdown
Anatomy
Toggle
Required
List
Required, but only visible when open
Toggle
Anatomy
Button
Icon
States
Button
Icon
Banner (highlight): 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 a disabled state for the Dropdown Toggle. Read more about when to enable vs hide
Size
ToggleButtons come in a Medium and Small size to allow for placement in ButtonSets with buttons of the same size.
Medium
- 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
- Integrate with Terraform Cloud
- Create a new run task in Terraform using the URL and key below.
-
Endpoint URL
-
HMAC Key
- Manage
- About
- Automate with Terraform
This component has been designed and implemented with accessibility in mind. When used as recommended, there should not be any accessibility issues with this component.
Known Potential Accessibility Issues
The following are known potential issues, and developers should keep these in mind when implementing this component:
- In any instance where data truncation occurs, there is no current method to access that data for the keyboard-only user. Therefore, we do not recommend allowing data to be truncated within this component.
- If the "overflow" toggle is used in the incorrect context, it will fail on perceivability. It must be used in in the current recommended context of a data table. For the best user experience, interactive elements should visually present as interactive, unless their context otherwise makes it clear that they are/should be interactive.
Applicable WCAG Success Criteria (Reference)
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.