AppDropdown
A menu of actions behind a single icon trigger — collapses a row of buttons into one tidy control.
<app-dropdown icon="more-horizontal" label="Row actions">…</app-dropdown><app-dropdown> hides a set of actions behind a single icon trigger — the classic “⋯” or kebab menu on a table row or card. It keeps a busy layout clean by collapsing three, four, or five actions into one control the user opens on demand.
Its look comes entirely from the shared @webority/theme, so the Razor <app-dropdown> and the React <AppDropdown> render identically — same trigger, same menu, same alignment on every Webority surface.
Playground
Every meaningful attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the menu above it.
icon, label, align and icon-size. Style a Razor toggle by targeting .topbar-icon-btn / .wui-dropdown-trigger from CSS instead.Items with icons
A leading icon on each item speeds recognition. Keep them consistent — either every item has one or none does.
Show code
<app-dropdown icon="more-horizontal" label="Row actions">
<button class="dropdown-item" type="button"><app-icon name="pencil"></app-icon> Edit</button>
<button class="dropdown-item" type="button"><app-icon name="files"></app-icon> Duplicate</button>
<button class="dropdown-item" type="button"><app-icon name="download"></app-icon> Export</button>
</app-dropdown>
Image icon
An item can lead with a picture instead of a glyph — an integration logo, a user avatar. Put an <img> (any URL, external included) inside the item; the theme sizes it to sit with the glyph items.
Show code
<app-dropdown icon="plus" label="Add integration">
<button class="dropdown-item" type="button"><img src="https://cdn.example.com/slack.png" alt="" /> Slack</button>
<button class="dropdown-item" type="button"><img src="https://cdn.example.com/github.png" alt="" /> GitHub</button>
</app-dropdown>
src can be an external CDN link, an uploaded avatar, or a data URI — it renders sized to match the glyph items, so a menu can mix logos and icons.Destructive items
A delete or remove item is marked danger so it reads red, and sits last — separated from the safe actions above it.
Show code
<app-dropdown icon="more-horizontal" label="Row actions">
<button class="dropdown-item" type="button"><app-icon name="pencil"></app-icon> Edit</button>
<button class="dropdown-item" type="button"><app-icon name="files"></app-icon> Duplicate</button>
<button class="dropdown-item danger" type="button"><app-icon name="trash-2"></app-icon> Delete</button>
</app-dropdown>
AppConfirmDialog so the action can't run by accident.Grouping with a divider
An <hr class="dropdown-divider"> renders a separator instead of an action — group related items apart from a destructive one, or separate navigation from actions.
Show code
<app-dropdown icon="more-horizontal" label="Row actions">
<button class="dropdown-item" type="button"><app-icon name="pencil"></app-icon> Edit</button>
<button class="dropdown-item" type="button"><app-icon name="files"></app-icon> Duplicate</button>
<hr class="dropdown-divider" />
<button class="dropdown-item danger" type="button"><app-icon name="trash-2"></app-icon> Delete</button>
</app-dropdown>
Rich content
Nested content isn't limited to .dropdown-item buttons — put any markup inside <app-dropdown> and it renders verbatim, for an identity block, a form, anything that isn't a flat action list. The icon toggle and react-bootstrap's open/close, outside-click, focus and Escape behavior are unchanged.
Show code
<app-dropdown icon="user" label="Account menu">
<div class="px-3 py-2 d-flex align-items-center gap-2">
<app-avatar name="Jane Doe"></app-avatar>
<div>
<div class="fw-semibold">Jane Doe</div>
<div class="text-muted small">jane@acme.com</div>
</div>
</div>
<hr class="dropdown-divider" />
<button class="dropdown-item" type="button">Account settings</button>
<button class="dropdown-item" type="button">Sign out</button>
</app-dropdown>
Show code
<app-dropdown icon="settings" label="View options">
<div class="px-3 py-2" style="min-width: 220px;">
<div class="fw-semibold mb-2">Row density</div>
<app-segmented label="Row density" name="density" value="cozy" size="sm" full-width="true">
<app-segmented-option value="compact" label="Compact" />
<app-segmented-option value="cozy" label="Cozy" />
<app-segmented-option value="roomy" label="Roomy" />
</app-segmented>
</div>
</app-dropdown>
AppDropdown, the Razor tag helper has no items attribute — content is always the nested markup, so there's nothing to choose between. Use flat .dropdown-item buttons for a plain action list, or richer markup like this whenever you need it.A custom trigger
Nest an <app-dropdown-toggle> slot for a rich control instead of the icon — an account chip, a labelled “Sort by” button. <app-dropdown> still owns the open/close, outside-click, focus and Escape behaviour; only the toggle's content changes.
Show code
<app-dropdown label="Account menu">
<app-dropdown-toggle>
<span class="d-inline-flex align-items-center gap-2">
<app-avatar name="Jane Doe"></app-avatar>
Jane Doe
<app-icon name="chevron-down" size="14"></app-icon>
</span>
</app-dropdown-toggle>
<button class="dropdown-item" type="button">Account settings</button>
<button class="dropdown-item" type="button">Sign out</button>
</app-dropdown>
<app-dropdown-toggle> is present it replaces the icon glyph in the toggle button, which switches to a reset wrapper (wui-dropdown-trigger) instead of the topbar icon button, so your trigger's own styling shows through unchanged.Alignment
The menu aligns to the end of the trigger by default — right-aligned, so it never spills off the edge of a row. Switch to start when the trigger sits on the left.
Show code
<app-dropdown icon="more-horizontal" label="Aligned end" align="end">…</app-dropdown> <app-dropdown icon="more-horizontal" label="Aligned start" align="start">…</app-dropdown>
When to use
Use it when
- A row or card has several secondary actions that would clutter the layout as buttons.
- You want a consistent “⋯” affordance for overflow actions across every row.
- The actions are related and belong under one grouped trigger.
Reach for something else when
- There is a single icon action. → AppActionIcon
- The action is the primary thing on the screen. → AppButton
- You are selecting one value from a list. → AppSelect
- You need a yes/no confirmation. → AppConfirmDialog
Best practices
Every option
The whole surface of the component, one cell per value — every alignment, every toggle shape, every item flavour, and the states an ordinary example never shows: an unnamed toggle, an empty menu.
align — both values
align="end"
align="start"
toggle — icon vs. custom trigger vs. unnamed
icon="more-horizontal" (default topbar-icon-btn)
app-dropdown-toggle (wui-dropdown-trigger, icon suppressed)
label="" — unnamed toggle
item flavours
icon per item
image item (logo/avatar)
danger class item
<hr class="dropdown-divider"> (separator between groups)
<a class="dropdown-item" href="…"> (navigation item)
(empty content) — empty menu
content mode — items vs. children
flat action list
rich, non-list content
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| (content) | markup | — | The menu items — one .dropdown-item element each (a <button> for an action, an <a> for navigation). |
| icon | string | three-dots | Bootstrap Icons glyph name for the trigger button. Ignored (the icon is not rendered) when an <app-dropdown-toggle> slot is nested. |
| label | string | Menu | Names the toggle and is its hover tooltip. Always set it. aria-label overrides it as the accessible name, exactly as in React. |
| align | start | end | end | Which edge of the trigger the menu aligns to. |
| icon-size | int | 20 | Trigger glyph size in px (React iconSize). |
| aria-label | string | — | Accessible name for the toggle, overriding label (React ariaLabel). With an <app-dropdown-toggle> slot the button is left unnamed unless this is set, because the trigger carries its own visible text. |
| toggleClassName / menuClassName | — | — | React-only; the tag helper does not expose a class override for the toggle or menu. Target .topbar-icon-btn / .wui-dropdown-trigger / .dropdown-menu from CSS instead. |
| linkComponent | — | — | React-only (router decoupling). Razor navigation items are always a plain <a class="dropdown-item" href="…">. |
| trigger | — | — | React-only prop; Razor reaches the same outcome with a nested <app-dropdown-toggle> child slot (see "A custom trigger" above). |
<button class="dropdown-item"> for an action, an <a class="dropdown-item"> for navigation, and add the danger class on a destructive one. A plain <hr class="dropdown-divider"> renders a separator.Open motion (product-level)
Every menu-like overlay — dropdowns, popovers, the select/date/phone panels — shares one entrance animation from the theme. It is a product-level choice on the root element, not a per-component attribute: menus are opened by Bootstrap internals, and mixing motions inside one product reads as a bug.
<html data-wui-menu-motion="drop"> — zoom + fade + a 6px drop out of the trigger (the default) · zoom — zoom + fade only, the quietest · spring — elastic overshoot, suits marketing surfaces · unfold — scales open vertically like a sheet · none — no entrance. Menus that flip upward animate from their bottom edge automatically, and everything is disabled under prefers-reduced-motion.