Dropdown

A dropdown menu component with positioning control, enhanced menu items, and keyboard navigation.

Basic Usage

The simplest dropdown uses trigger_text to auto-generate a button trigger.

<c-ui.dropdown trigger_text="Account">
    <c-ui.dropdown.item>Profile</c-ui.dropdown.item>
    <c-ui.dropdown.item>Settings</c-ui.dropdown.item>
    <c-ui.dropdown.item>Logout</c-ui.dropdown.item>
</c-ui.dropdown>
{% cotton ui.dropdown trigger_text="Account" %}
    {% cotton ui.dropdown.item %}Profile{% endcotton %}
    {% cotton ui.dropdown.item %}Settings{% endcotton %}
    {% cotton ui.dropdown.item %}Logout{% endcotton %}
{% endcotton %}

Positioning

Control dropdown placement with position, align, and offset props. By default, dropdowns auto-adjust to stay within the viewport (disable with :auto_position="False").

<c-ui.dropdown position="bottom" align="start" offset="8" trigger_text="Bottom Start">
    <c-ui.dropdown.item>Option 1</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 2</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 3</c-ui.dropdown.item>
</c-ui.dropdown>

<c-ui.dropdown position="bottom" align="end" offset="8" trigger_text="Bottom End">
    <c-ui.dropdown.item>Option 1</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 2</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 3</c-ui.dropdown.item>
</c-ui.dropdown>

<c-ui.dropdown position="top" align="start" offset="8" trigger_text="Top Start">
    <c-ui.dropdown.item>Option 1</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 2</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 3</c-ui.dropdown.item>
</c-ui.dropdown>

<c-ui.dropdown position="top" align="end" offset="8" trigger_text="Top End">
    <c-ui.dropdown.item>Option 1</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 2</c-ui.dropdown.item>
    <c-ui.dropdown.item>Option 3</c-ui.dropdown.item>
</c-ui.dropdown>
{% cotton ui.dropdown position="bottom" align="start" offset="8" trigger_text="Bottom Start" %}
    {% cotton ui.dropdown.item %}Option 1{% endcotton %}
    {% cotton ui.dropdown.item %}Option 2{% endcotton %}
    {% cotton ui.dropdown.item %}Option 3{% endcotton %}
{% endcotton %}

{% cotton ui.dropdown position="bottom" align="end" offset="8" trigger_text="Bottom End" %}
    {% cotton ui.dropdown.item %}Option 1{% endcotton %}
    {% cotton ui.dropdown.item %}Option 2{% endcotton %}
    {% cotton ui.dropdown.item %}Option 3{% endcotton %}
{% endcotton %}

{% cotton ui.dropdown position="top" align="start" offset="8" trigger_text="Top Start" %}
    {% cotton ui.dropdown.item %}Option 1{% endcotton %}
    {% cotton ui.dropdown.item %}Option 2{% endcotton %}
    {% cotton ui.dropdown.item %}Option 3{% endcotton %}
{% endcotton %}

{% cotton ui.dropdown position="top" align="end" offset="8" trigger_text="Top End" %}
    {% cotton ui.dropdown.item %}Option 1{% endcotton %}
    {% cotton ui.dropdown.item %}Option 2{% endcotton %}
    {% cotton ui.dropdown.item %}Option 3{% endcotton %}
{% endcotton %}

Responsive positioning

With :auto_position (on by default) the menu watches the viewport and flips or realigns to stay visible. Drag the handle to shrink the preview into a mini viewport and watch the open menu reposition.

Item Variants

Enhance items with icons, keyboard shortcuts, and danger variants.

<c-ui.dropdown trigger_text="Actions">
    <c-ui.dropdown.item kbd="⌘E">
        <c-slot name="icon">
            <svg>...</svg>
        </c-slot>
        Edit
    </c-ui.dropdown.item>
    <c-ui.dropdown.item kbd="⌘D">
        <c-slot name="icon">
            <svg>...</svg>
        </c-slot>
        Duplicate
    </c-ui.dropdown.item>
    <c-ui.dropdown.separator />
    <c-ui.dropdown.item variant="danger" kbd="⌘⌫">
        <c-slot name="icon">
            <svg>...</svg>
        </c-slot>
        Delete
    </c-ui.dropdown.item>
</c-ui.dropdown>
{% cotton ui.dropdown trigger_text="Actions" %}
    {% cotton ui.dropdown.item kbd="⌘E" %}
        {% cotton:slot icon %}
            <svg>...</svg>
        {% endcotton:slot %}
        Edit
    {% endcotton %}
    {% cotton ui.dropdown.item kbd="⌘D" %}
        {% cotton:slot icon %}
            <svg>...</svg>
        {% endcotton:slot %}
        Duplicate
    {% endcotton %}
    {% cotton ui.dropdown.separator /%}
    {% cotton ui.dropdown.item variant="danger" kbd="⌘⌫" %}
        {% cotton:slot icon %}
            <svg>...</svg>
        {% endcotton:slot %}
        Delete
    {% endcotton %}
{% endcotton %}

Custom Trigger

Use the trigger slot for complete control over the trigger element. Common uses include icon-only buttons, avatar menus, or custom styled triggers.

<!-- Icon-only menu button -->
<c-ui.dropdown position="bottom" align="end">
    <c-slot name="trigger">
        <button type="button" class="p-2 rounded-md hover:bg-zinc-100" aria-label="More options">
            <svg class="w-5 h-5"><!-- three dots icon --></svg>
        </button>
    </c-slot>
    <c-ui.dropdown.item>Edit</c-ui.dropdown.item>
    <c-ui.dropdown.item>Duplicate</c-ui.dropdown.item>
    <c-ui.dropdown.separator />
    <c-ui.dropdown.item variant="danger">Delete</c-ui.dropdown.item>
</c-ui.dropdown>

<!-- User avatar menu -->
<c-ui.dropdown position="bottom" align="end">
    <c-slot name="trigger">
        <button class="flex items-center gap-2 rounded-full hover:bg-zinc-100">
            <div class="w-8 h-8 rounded-full bg-accent text-white">JD</div>
            <svg><!-- chevron --></svg>
        </button>
    </c-slot>
    <c-ui.dropdown.item>My Profile</c-ui.dropdown.item>
    <c-ui.dropdown.item>Account Settings</c-ui.dropdown.item>
    <c-ui.dropdown.separator />
    <c-ui.dropdown.item>Sign Out</c-ui.dropdown.item>
</c-ui.dropdown>
<!-- Icon-only menu button -->
{% cotton ui.dropdown position="bottom" align="end" %}
    {% cotton:slot trigger %}
        <button type="button" class="p-2 rounded-md hover:bg-zinc-100" aria-label="More options">
            <svg class="w-5 h-5"><!-- three dots icon --></svg>
        </button>
    {% endcotton:slot %}
    {% cotton ui.dropdown.item %}Edit{% endcotton %}
    {% cotton ui.dropdown.item %}Duplicate{% endcotton %}
    {% cotton ui.dropdown.separator /%}
    {% cotton ui.dropdown.item variant="danger" %}Delete{% endcotton %}
{% endcotton %}

<!-- User avatar menu -->
{% cotton ui.dropdown position="bottom" align="end" %}
    {% cotton:slot trigger %}
        <button class="flex items-center gap-2 rounded-full hover:bg-zinc-100">
            <div class="w-8 h-8 rounded-full bg-accent text-white">JD</div>
            <svg><!-- chevron --></svg>
        </button>
    {% endcotton:slot %}
    {% cotton ui.dropdown.item %}My Profile{% endcotton %}
    {% cotton ui.dropdown.item %}Account Settings{% endcotton %}
    {% cotton ui.dropdown.separator /%}
    {% cotton ui.dropdown.item %}Sign Out{% endcotton %}
{% endcotton %}

Separators & States

Use separators to group menu items. Items can be disabled or rendered as links.

<c-ui.dropdown trigger_text="Menu">
    <c-ui.dropdown.item href="/profile">View Profile</c-ui.dropdown.item>
    <c-ui.dropdown.item>Edit Profile</c-ui.dropdown.item>
    <c-ui.dropdown.separator />
    <c-ui.dropdown.item>Settings</c-ui.dropdown.item>
    <c-ui.dropdown.item disabled>Upgrade Plan</c-ui.dropdown.item>
    <c-ui.dropdown.separator />
    <c-ui.dropdown.item variant="danger">Sign Out</c-ui.dropdown.item>
</c-ui.dropdown>
{% cotton ui.dropdown trigger_text="Menu" %}
    {% cotton ui.dropdown.item href="/profile" %}View Profile{% endcotton %}
    {% cotton ui.dropdown.item %}Edit Profile{% endcotton %}
    {% cotton ui.dropdown.separator /%}
    {% cotton ui.dropdown.item %}Settings{% endcotton %}
    {% cotton ui.dropdown.item disabled %}Upgrade Plan{% endcotton %}
    {% cotton ui.dropdown.separator /%}
    {% cotton ui.dropdown.item variant="danger" %}Sign Out{% endcotton %}
{% endcotton %}

Grouped Menus

Organize menu items into labeled groups using <c-ui.dropdown.group>.

<c-ui.dropdown trigger_text="File">
    <c-ui.dropdown.group label="Edit">
        <c-ui.dropdown.item kbd="⌘Z">
            <c-slot name="icon">
                <svg><!-- Undo icon --></svg>
            </c-slot>
            Undo
        </c-ui.dropdown.item>
        <c-ui.dropdown.item kbd="⌘⇧Z">
            <c-slot name="icon">
                <svg><!-- Redo icon --></svg>
            </c-slot>
            Redo
        </c-ui.dropdown.item>
    </c-ui.dropdown.group>

    <c-ui.dropdown.separator />

    <c-ui.dropdown.group label="File">
        <c-ui.dropdown.item kbd="⌘S">
            <c-slot name="icon">
                <svg><!-- Save icon --></svg>
            </c-slot>
            Save
        </c-ui.dropdown.item>
        <c-ui.dropdown.item kbd="⌘O">
            <c-slot name="icon">
                <svg><!-- Open icon --></svg>
            </c-slot>
            Open
        </c-ui.dropdown.item>
    </c-ui.dropdown.group>

    <c-ui.dropdown.separator />

    <c-ui.dropdown.item variant="danger" kbd="⌘Q">
        <c-slot name="icon">
            <svg><!-- Quit icon --></svg>
        </c-slot>
        Quit
    </c-ui.dropdown.item>
</c-ui.dropdown>
{% cotton ui.dropdown trigger_text="File" %}
    {% cotton ui.dropdown.group label="Edit" %}
        {% cotton ui.dropdown.item kbd="⌘Z" %}
            {% cotton:slot icon %}
                <svg><!-- Undo icon --></svg>
            {% endcotton:slot %}
            Undo
        {% endcotton %}
        {% cotton ui.dropdown.item kbd="⌘⇧Z" %}
            {% cotton:slot icon %}
                <svg><!-- Redo icon --></svg>
            {% endcotton:slot %}
            Redo
        {% endcotton %}
    {% endcotton %}

    {% cotton ui.dropdown.separator /%}

    {% cotton ui.dropdown.group label="File" %}
        {% cotton ui.dropdown.item kbd="⌘S" %}
            {% cotton:slot icon %}
                <svg><!-- Save icon --></svg>
            {% endcotton:slot %}
            Save
        {% endcotton %}
        {% cotton ui.dropdown.item kbd="⌘O" %}
            {% cotton:slot icon %}
                <svg><!-- Open icon --></svg>
            {% endcotton:slot %}
            Open
        {% endcotton %}
    {% endcotton %}

    {% cotton ui.dropdown.separator /%}

    {% cotton ui.dropdown.item variant="danger" kbd="⌘Q" %}
        {% cotton:slot icon %}
            <svg><!-- Quit icon --></svg>
        {% endcotton:slot %}
        Quit
    {% endcotton %}
{% endcotton %}

API Reference

Dropdown Props
Name Description Type Options Default
position Dropdown position relative to trigger. str top, bottom, left, right bottom
align Dropdown alignment relative to position. str start, center, end start
offset Distance in pixels from the trigger. str Any number 4
trigger_text Auto-generates a trigger button with this text. Use this OR the trigger slot, not both. str Any text
min_width Minimum width of dropdown content. str Any CSS width value 12rem
auto_position Automatically adjusts position and alignment to keep dropdown in viewport. Detects screen boundaries and intelligently repositions to prevent overflow. Set to False to disable. bool True (default), False True
Dropdown Slots
Name Description Type Options Default
trigger Custom trigger element. If not provided, trigger_text is required. Optional
slot (default) Dropdown menu content. Place items directly or wrap in &lt;c-ui.dropdown.group&gt; for organization. Required
Dropdown.item Props
Name Description Type Options Default
icon Icon displayed before item text. slot Any SVG or icon component
kbd Keyboard shortcut displayed on the right (e.g., ⌘K). str Any text
variant Visual variant for the item. str danger, (empty for default)
disabled Disables the item. bool True, False False
href If provided, renders as a link (&lt;a&gt;) instead of button. str Any URL
Dropdown.separator

<c-ui.dropdown.separator /> - Horizontal divider for grouping menu items. No props required.

Dropdown.group Props
Name Description Type Options Default
label Group heading displayed above items in uppercase gray text. str Any text
slot (default) Group content. Place &lt;c-ui.dropdown.item&gt; components here. Dropdown items Required
Accessibility
  • Keyboard Navigation: Arrow up/down to navigate items, Home/End to jump, Escape to close, Tab to close
  • ARIA Roles: Proper menu/menuitem roles for screen readers
  • Focus Management: Focus trap when open, auto-focus first item on open
  • Visual Indicators: Hover and focus states on all interactive elements