overlays
Dropdown
A button that opens a short list of actions or links next to it.
Native behaviorUses built-in HTML behavior, so you write no script.
Usage
The button opens the menu with popovertarget. Each action closes it with popovertargetaction="hide".
<div class="ca-dropdown">
<button class="ca-button ca-button--outline ca-button--md" type="button" popovertarget="project-actions">Project actions</button>
<div class="ca-dropdown__menu" id="project-actions" popover>
<button class="ca-dropdown__item" type="button" popovertarget="project-actions" popovertargetaction="hide">Rename project</button>
<button class="ca-dropdown__item" type="button" popovertarget="project-actions" popovertargetaction="hide">Duplicate project</button>
<hr class="ca-dropdown__separator" />
<button class="ca-dropdown__item" type="button" popovertarget="project-actions" popovertargetaction="hide">Delete project</button>
</div>
</div>Examples
Links and a label
Items can be links. A label names the group; a separator splits it.
<div class="ca-dropdown">
<button class="ca-button ca-button--ghost ca-button--md" type="button" popovertarget="account-menu">Your account</button>
<div class="ca-dropdown__menu" id="account-menu" popover>
<p class="ca-dropdown__label">Signed in as sam@example.com</p>
<a class="ca-dropdown__item" href="#profile">Profile</a>
<a class="ca-dropdown__item" href="#billing">Billing</a>
<hr class="ca-dropdown__separator" />
<a class="ca-dropdown__item" href="#sign-out">Sign out</a>
</div>
</div>Unavailable item
Use aria-disabled="true" and point aria-describedby at the reason, so people can still find the item and learn why.
<div class="ca-dropdown">
<button class="ca-button ca-button--outline ca-button--md" type="button" popovertarget="invoice-actions">Invoice actions</button>
<div class="ca-dropdown__menu" id="invoice-actions" popover>
<button class="ca-dropdown__item" type="button" popovertarget="invoice-actions" popovertargetaction="hide">Download PDF</button>
<button class="ca-dropdown__item" type="button" aria-disabled="true" aria-describedby="invoice-paid">Send reminder</button>
<p class="ca-dropdown__label" id="invoice-paid">Paid invoices need no reminder.</p>
</div>
</div>Guidance and accessibility
When to use
- Use a dropdown for a handful of actions or links that do not fit next to the content, such as the actions on a project or the links of an account.
- Name the trigger after what is inside: “Project actions”, not “More”. The core adds a chevron after the label, so people see that the button opens a menu; it turns over while the menu is open.
- Keep it short. More than about eight items, or items people need to compare, belong on the page.
- For picking a value in a form, use a select, not a dropdown.
Accessibility
- The menu is a native popover. The browser closes it on Escape and on a click outside, and returns focus to the button. Browsers tell screen readers whether the menu is open.
- Items are in the tab order right after the button, so Tab moves through
them. This is the disclosure pattern; do not add
role="menu", which promises arrow-key navigation the dropdown does not have. - Give an action that does something on the page
popovertargetwithpopovertargetaction="hide", so the menu closes and focus returns to the button. - On touch screens every item is at least 44 pixels tall.
- The chevron is decoration. Screen readers hear whether the menu is open (expanded or collapsed) from the button itself, and the label says what is inside. In forced colors the chevron takes the button text color.
- The menu uses CSS anchor positioning. Browsers without it show the menu in the middle of the screen, where it still works.
Classes
Generated from the component contract. Parts use __, modifiers use --.
| Class | Kind | Use it for |
|---|---|---|
ca-dropdown | Component | Wrapper around the trigger button and its menu; adds the chevron to the button. |
ca-dropdown__menu | Part | The [popover] panel; sits under the button and flips when there is no room. |
ca-dropdown__item | Part | An action (<button>) or a link (<a>) in the menu. |
ca-dropdown__label | Part | Text that names a group or explains an item. |
ca-dropdown__separator | Part | An <hr> between groups. |
Skins
The same markup, dressed by each skin. Structure and behavior stay the same; only the look changes.
Base skin
Neutral grayscale starting point; product skins extend it and change what differs.
Calaca skin
The Calaca UI brand: hueso paper and tinta ink, cempasúchil marigold, rosa and jade.
Proof skin
Pilot skin pushed far from base: square, heavy, offset shadows, larger targets.
Crossview skin
The CrossView proofing table: cool ground, bond-paper sheets, rule-grey hairlines, one red mark.
Framework notes
Link the prebuilt stylesheet of your skin next to your brand theme. No build step.
<link rel="stylesheet" href="theme.css" />
<link rel="stylesheet" href="ca-base.css" />In Astro, Vite and other Tailwind projects, import Calaca after Tailwind and your theme in your main stylesheet.
@import "tailwindcss";
@import "./theme.css";
@import "@calaca/ui/core.css";
@import "@calaca/ui/skins/base.css";Same stylesheet as above; write the classes in className.
<button className="ca-button ca-button--primary ca-button--md" type="button">Save changes</button>