Skip to content

Dropdown ​

te-dropdown is a button and a menu panel. The panel is a native popover, so the browser handles dismissal: clicking anywhere else closes it, Esc closes it, and it renders in the top layer — never clipped by a parent's overflow, never in a z-index fight. The only thing the component adds is placing the panel against its trigger.

Usage ​

vue
<te-dropdown
  label="Actions"
  :items="['Edit', 'Duplicate', { label: 'Delete', disabled: true }]"
  @select="picked = $event.label"
/>

Items are plain strings or { label, disabled } objects, the same shape te-list-group takes.

Alignment ​

align="end" lines the panel up with the trigger's right edge. It is a preference, not a promise: the panel is clamped to the viewport, and flips above the trigger when there is no room below.

vue
<te-dropdown label="Aligned end" align="end" :items="['One', 'Two']" />

Custom trigger and content ​

The trigger slot replaces the button's label; the default slot replaces the whole item list. Anything you put in the default slot still closes the menu when a button or a inside it is clicked, unless you set :close-on-select="false".

vue
<te-dropdown type="primary">
  <template #trigger>Settings ▾</template>
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Billing</button>
</te-dropdown>

Controlled ​

v-model reflects and drives the open state.

vue
<te-button @click="open = !open">Toggle from outside</te-button>
<te-dropdown v-model="open" label="Menu" :items="['One', 'Two']" />

Keyboard ​

Enter, Space or ↓ on the trigger opens the menu and lands on the first item; ↑ opens it on the last. A click with the mouse leaves the focus alone. Disabled items are skipped, and the arrows work on whatever the default slot renders, not only on items.

KeyDoes
↑ ↓Previous / next item.
Home EndFirst / last item.
Enter SpaceActivate the focused item.
EscClose and go back to the trigger — the popover's own behaviour.
TabClose and move on.

Props ​

PropTypeDefaultDescription
modelValuebooleanfalseOpen state. Supports v-model.
items(string | { label, disabled })[][]Menu entries. Ignored when the default slot is used.
labelstring''Trigger text. Ignored when the trigger slot is used.
align'start' | 'end''start'Edge of the trigger the panel lines up with.
typeVariant'light'Trigger colour, same set as te-button.
size'small' | 'medium' | 'large''medium'Trigger size.
disabledbooleanfalseDisables the trigger.
closeOnSelectbooleantrueA click on a button or a inside the panel closes it.

Events ​

EventPayloadDescription
update:modelValuebooleanOpen state changed, including a browser-driven dismissal.
select(item, index)An entry from items was clicked. Not emitted for default-slot content.

Slots ​

SlotPropsDescription
trigger—Replaces the trigger's label.
default—Replaces the item list. Style entries with class="dropdown-item".

Browser support ​

The panel needs the Popover API (Chrome 114, Firefox 125, Safari 17). Where it is missing, the trigger and v-model simply do nothing rather than throwing.