Interactive

Basic Dropdown

A styled select dropdown with animated chevron and custom item rendering.

A dropdown component built on Nuxt UI's USelect and Reka UI primitives, with a rotating chevron animation and custom item rendering that includes icons and a checkmark indicator. It supports both controlled (v-model) and uncontrolled modes, with motion-v powered animations.

Usage

Provide an array of items with id, label, and optional icon. Use v-model for controlled selection, or listen to @change for uncontrolled mode.

<template>
  <div class="flex w-full max-w-md justify-center">
    <MBasicDropdown
      :items="items"
      label="Select option"
      @change="onChange"
    />
  </div>
</template>

<script setup lang="ts">
const items = [
  { id: '1', label: 'Option 1', icon: 'i-lucide-circle' },
  { id: '2', label: 'Option 2', icon: 'i-lucide-square' },
  { id: '3', label: 'Option 3', icon: 'i-lucide-triangle' },
]

const onChange = (_item) => {
  // handle selection
}
</script>

Customize

Customize

Label
Model Value

Props

Prop Type Default Description
classstringundefinedAdditional CSS classes applied to the trigger.
itemsDropdownItem[]requiredArray of dropdown items to display.
modelValueDropdownItem | null | undefinedundefinedControlled selected item. When undefined, component is uncontrolled.
labelstring''Label shown in the trigger when no item is selected.

Events

Event Payload Description
change(item: DropdownItem) => voidEmitted when an item is selected in uncontrolled mode.
update:modelValue(value: DropdownItem | null) => voidEmitted when selection changes in controlled mode.

Slots

Slot Props Description
item(props: { item: DropdownItem }) => voidCustom item rendering slot. By default, renders icon, label, and checkmark for selected item.
trailing(props: { open: boolean }) => voidCustom trailing slot. By default, renders an animated chevron.

Types

Prop Type Default Description
DropdownItem{ id: string | number, icon?: string, label: string }-Interface for dropdown items.

UI

This component's theme exposes the slots below. Override any of them per instance with the ui prop, or app-wide under ui.basicDropdown in app.config.ts.

Prop Type Default Description
uiobject-Per-slot classes merged over the theme defaults.
Slot Props Description
root-
base-m-basic-dropdown__trigger min-h-[44px] w-full justify-between gap-2 rounded-lg px-4 text-left
trailing-pe-4
content-m-basic-dropdown__content rounded-lg
group-m-basic-dropdown__group
item-m-basic-dropdown__item
itemLabel-m-basic-dropdown__item-label
viewport-m-basic-dropdown__viewport
itemLeadingIcon-size-5 shrink-0
itemWrapper-m-basic-dropdown__item-wrapper
itemTrailing-m-basic-dropdown__item-trailing
itemTrailingIcon-m-basic-dropdown__check
checkIcon-h-4 w-4 text-primary
chevronIcon-h-4 w-4

Accessibility

The dropdown uses Nuxt UI's USelect which provides proper ARIA semantics (role="combobox", role="listbox", aria-haspopup, aria-expanded, aria-selected). The custom checkmark SVG includes a <title>Selected</title> for screen readers. Focus is managed by Reka UI primitives with keyboard support (Arrow keys, Enter, Space, Escape). The trigger has aria-label that combines the label and selected item. Focus-visible rings are styled for keyboard navigation.

Performance

  • Chevron rotation is animated with motion-v (duration: 0.2s) and respects prefers-reduced-motion (falls back to instant rotation when reduced motion is preferred).
  • Content animations are handled by Reka UI's SelectContent with CSS keyframe animations scoped via data attributes.
  • Custom item rendering reuses Reka UI's SelectItemText to preserve proper ARIA relationships (labeling the option correctly).
  • Collision padding (8px) is applied to prevent panel from going off-screen without heavy repositioning.
  • The component avoids unnecessary re-renders by using computed properties and proper controlled/uncontrolled state management.
The dropdown accepts any standard HTML attributes via v-bind="$attrs", which are forwarded to the underlying SelectTrigger (since USelect forwards attrs appropriately).
Copyright © 2026