Skip to content

@vibe-labs/design-components-dropdowns

Dropdown menu component tokens, styles, and TypeScript types for the Vibe Design System.

Installation

bash
npm install @vibe-labs/design-components-dropdowns
css
@import "@vibe-labs/design-components-dropdowns";
ts
import { DropdownAlignments, DropdownItemVariants } from "@vibe-labs/design-components-dropdowns/types";
import type { DropdownMenuStyleProps, DropdownItemStyleProps } from "@vibe-labs/design-components-dropdowns/types";

Contents

Tokens

CSS custom properties defined in @layer vibe.tokens (file: dropdown.css).

TokenDefaultDescription
--dropdown-bg--surface-elevatedMenu background
--dropdown-border-color--border-subtleMenu border
--dropdown-border-width--border-width-1Border width
--dropdown-radius--radius-lgBorder radius
--dropdown-shadow--shadow-lgBox shadow
--dropdown-padding--space-1Inner padding
--dropdown-min-width10remMinimum width
--dropdown-max-height20remMax height (scrollable)
--dropdown-z--z-dropdown (100)Z-index

Items

TokenDefaultDescription
--dropdown-item-height2remMinimum item height
--dropdown-item-px--space-2Horizontal padding
--dropdown-item-radius--radius-smItem border radius
--dropdown-item-font-size--text-smFont size
--dropdown-item-color--text-primaryText color
--dropdown-item-hover-bg--surface-hover-overlayHover background
--dropdown-item-active-bg--surface-active-overlayActive background
--dropdown-item-disabled-opacity--input-disabled-opacityDisabled state opacity

Groups

TokenDefaultDescription
--dropdown-group-label-font-size--text-xsGroup label size
--dropdown-group-label-color--text-mutedGroup label color
--dropdown-divider-color--border-subtleDivider color

Generated Styles

Component classes generated into @layer vibe.components (file: dropdown.g.css).

Elements

ClassDescription
.dropdownRelative positioned inline-flex wrapper
.dropdown-menuAbsolutely positioned panel (hidden by default, flex column when open)
.dropdown-itemFull-width interactive row with hover/active/focus/disabled states
.dropdown-item-iconLeading icon slot (1rem, muted)
.dropdown-item-trailTrailing content (auto margin-left, muted, xs text)
.dropdown-item-descDescription text below item (xs, muted, wraps)
.dropdown-groupFlex column container for grouped items
.dropdown-group-labelUppercase section label
.dropdown-dividerHorizontal rule between sections
ValuePosition
bottom-startBelow, left-aligned
bottom-endBelow, right-aligned
bottom-centerBelow, centered
top-startAbove, left-aligned
top-endAbove, right-aligned

Set via data-align on .dropdown-menu.

Item Variants

data-variant="danger" — red text with danger-subtle hover background.

Selection States

Items with aria-selected="true" or aria-checked="true" receive hover overlay background and semibold weight.

Modifiers

ModifierDescription
data-openShows menu with fade-in animation
data-fullMenu matches trigger width

TypeScript Types

ts
DropdownAlignments   // ["bottom-start", "bottom-end", "bottom-center", "top-start", "top-end"]
DropdownItemVariants // ["danger"]

type DropdownAlignment
type DropdownItemVariant

interface DropdownStyleProps {}
interface DropdownMenuStyleProps { align?: DropdownAlignment; open?: boolean; full?: boolean }
interface DropdownItemStyleProps { variant?: DropdownItemVariant; disabled?: boolean }
interface DropdownItemIconStyleProps {}
interface DropdownItemTrailStyleProps {}
interface DropdownItemDescStyleProps {}
interface DropdownGroupStyleProps {}
interface DropdownGroupLabelStyleProps {}
interface DropdownDividerStyleProps {}

Dist Structure

FileDescription
index.cssBarrel — imports tokens + generated styles
dropdown.cssToken definitions
dropdown.g.cssGenerated component styles
index.js / index.d.tsTypeScript types + runtime constants

Dependencies

Requires tokens from @vibe-labs/design (surfaces, borders, spacing, typography, elevation, transitions, z-index).

Build

bash
npm run build

Usage Guide

Import

css
@import "@vibe-labs/design-components-dropdowns";
ts
import type { DropdownMenuStyleProps, DropdownItemStyleProps } from "@vibe-labs/design-components-dropdowns/types";

Variants

Set data-align on .dropdown-menu: bottom-start (default) · bottom-end · bottom-center · top-start · top-end

Item variant

Set data-variant on .dropdown-item: omit for default · danger

Boolean flags on .dropdown-menu

  • data-open — shows the menu with fade-in animation
  • data-full — menu width matches the trigger button width

Item states

  • data-disabled on .dropdown-item — reduces opacity, disables pointer events
  • aria-selected="true" or aria-checked="true" on .dropdown-item — shows selected state (semibold, overlay bg)

Examples

Basic dropdown

html
<!-- Toggle data-open to show/hide the menu -->
<div class="dropdown">
  <button class="btn" data-variant="secondary" aria-haspopup="true" aria-expanded="true">
    Options
  </button>

  <div class="dropdown-menu" data-align="bottom-start" data-open>
    <button class="dropdown-item">Edit</button>
    <button class="dropdown-item">Duplicate</button>
    <div class="dropdown-divider"></div>
    <button class="dropdown-item" data-variant="danger">Delete</button>
  </div>
</div>

Items with icons and trailing text

html
<div class="dropdown-menu" data-align="bottom-start" data-open>
  <button class="dropdown-item">
    <span class="dropdown-item-icon">
      <svg><!-- icon --></svg>
    </span>
    Copy link
    <span class="dropdown-item-trail">⌘C</span>
  </button>
  <button class="dropdown-item">
    <span class="dropdown-item-icon">
      <svg><!-- icon --></svg>
    </span>
    Share
  </button>
</div>

Items with descriptions

html
<div class="dropdown-menu" data-align="bottom-start" data-open>
  <button class="dropdown-item">
    Public
    <span class="dropdown-item-desc">Anyone with the link can view.</span>
  </button>
  <button class="dropdown-item" aria-selected="true">
    Team only
    <span class="dropdown-item-desc">Only team members can view.</span>
  </button>
  <button class="dropdown-item">
    Private
    <span class="dropdown-item-desc">Only you can view.</span>
  </button>
</div>

Grouped items

html
<div class="dropdown-menu" data-align="bottom-start" data-open>
  <div class="dropdown-group">
    <div class="dropdown-group-label">Account</div>
    <button class="dropdown-item">Profile</button>
    <button class="dropdown-item">Settings</button>
  </div>
  <div class="dropdown-divider"></div>
  <div class="dropdown-group">
    <div class="dropdown-group-label">Danger zone</div>
    <button class="dropdown-item" data-variant="danger">Sign out</button>
  </div>
</div>

Full-width dropdown (matches trigger)

html
<div class="dropdown" style="width: 100%">
  <button class="btn" data-variant="secondary" data-full>Select option</button>
  <div class="dropdown-menu" data-full data-open>
    <button class="dropdown-item">Option A</button>
    <button class="dropdown-item">Option B</button>
  </div>
</div>

With Vue

Use @vibe-labs/design-vue-dropdowns for <SbDropdown>, <SbDropdownMenu>, and <SbDropdownItem> which manage open/close state and map DropdownMenuStyleProps to data attributes.

Vibe