v4.0.0-beta.4

Dropdown

<BaseDropdown /> · An options or a contextual menu.

vue
<template>
  <BaseDropdown variant="default" label="Default dropdown">
    <BaseDropdownItem>Leads</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Reports</BaseDropdownItem>
    <BaseDropdownItem>
      Settings
      <template #end>
        <BaseKbd size="sm">
          <span class="text-xs font-mono">⌘</span>
        </BaseKbd>
        <BaseKbd size="sm">
          <span class="text-xs font-mono px-0.5">P</span>
        </BaseKbd>
      </template>
    </BaseDropdownItem>
  </BaseDropdown>
</template>

Features

  • Can be controlled or uncontrolled
  • Supports submenus with configurable reading direction
  • Supports items, labels, groups of items
  • Supports checkable items
  • Full keyboard navigation
  • Handles accessibility

Anatomy

This component has optional sub components that you can use to create your dropdown menu. You can customize the dropdown's visual style by using the available props.

vue
<template>
  <BaseDropdown>
    <BaseDropdownLabel>
      <!-- Label goes here -->
    </BaseDropdownLabel>
    <!-- Sub dropdown -->
    <BaseDropdownSub>
      <template #title>
        <!-- Sub dropdown title goes here -->
      </template>
      <BaseDropdownLabel>
        <!-- Sub dropdown label goes here -->
      </BaseDropdownLabel>
      <BaseDropdownItem>
        <!-- Sub dropdown item content goes here -->
      </BaseDropdownItem>
    </BaseDropdownSub>
    <!-- Separator item -->
    <BaseDropdownSeparator />
    <BaseDropdownItem>
      <!-- Item content goes here -->
    </BaseDropdownItem>
    <!-- Checkbox item -->
    <BaseDropdownCheckbox />
    <!-- Radio group -->
    <BaseDropdownRadioGroup>
      <!-- Radio item -->
      <BaseDropdownRadio />
    </BaseDropdownRadioGroup>
    <!-- Menu top arrow -->
    <BaseDropdownArrow />
  </BaseDropdown>
</template>

API Reference

This component has props that you can use to modify its visual style.

Prop Type
label
default:""
string

The label to display for the dropdown.

disabled
default:-
boolean

Disables the dropdown.

variant
default:"default"
"default" | "primary" | "none" | "muted"

The variant of the dropdown content

rounded
default:"md"
"none" | "md" | "sm" | "lg" | "full"

The radius of the dropdown button.

bindings
default:{}
{ content?: DropdownMenuContentProps; trigger?: DropdownMenuTriggerProps; portal?: DropdownMenuPortalProps; }

Optional bindings to pass to the inner components.

classes
default:{}
{ content?: string | string[]; }

Optional classes to pass to the inner components.

default-open
default:-
boolean

The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state.

open
default:-
boolean

The controlled open state of the menu. Can be used as `v-model:open`.

dir
default:-
Direction_3

The reading direction of the combobox when applicable. If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode.

modal
default:-
boolean

The modality of the dropdown menu. When set to `true`, interaction with outside elements will be disabled and only menu content will be visible to screen readers.

Event Emitted Value Type
update:open
[payload: boolean]
Slot Type
#default
any
#button
any
#label
any
Prop Type
title
default:""
string

The title to display for the dropdown item.

text
default:""
string

The text to display for the dropdown item.

variant
default:-
"default" | "primary" | "none" | "muted"

The hover color of the dropdown-item inner elements.

rounded
default:-
"none" | "md" | "sm" | "lg" | "full"

The radius of the dropdown-item.

disabled
default:-
boolean

When `true`, prevents the user from interacting with the item.

text-value
default:-
string

Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. <br> Use this when the content is complex, or you have non-textual content inside.

as-child
default:-
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.

as
default:-
AsTag | Component

The element or component this component should render as. Can be overwritten by `asChild`.

Event Emitted Value Type
select
[event: Event]
Slot Type
#default
any
#title
any
#text
any
#start
any
#end
any
Prop Type
title
default:-
string

The title to display for the dropdown item.

text
default:-
string

The text to display for the dropdown item.

variant
default:-
"default" | "primary" | "none" | "muted"

The variant of the dropdown content

rounded
default:-
"none" | "md" | "sm" | "lg" | "full"

The radius of the dropdown button.

bindings
default:-
{ trigger?: DropdownMenuSubTriggerProps; content?: DropdownMenuSubContentProps; portal?: DropdownMenuPortalProps; }

Optional bindings to pass to the inner components.

default-open
default:-
boolean

The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state.

open
default:-
boolean

The controlled open state of the menu. Can be used as `v-model:open`.

Event Emitted Value Type
update:open
[payload: boolean]
Slot Type
#default
any
#title
any
#text
any

Checkbox item

Model Type
model-value
CheckedState

The controlled checked state of the item. Can be used as `v-model`.

Prop Type
title
default:""
string

The title to display for the dropdown item.

text
default:""
string

The text to display for the dropdown item.

variant
default:-
"default" | "primary" | "none" | "muted"

The hover color of the dropdown-item inner elements.

rounded
default:-
"none" | "md" | "sm" | "lg"

The radius of the dropdown-item.

bindings
default:{}
{ indicator?: DropdownMenuItemIndicatorProps; }

Optional bindings to pass to the inner components.

disabled
default:-
boolean

When `true`, prevents the user from interacting with the item.

text-value
default:-
string

Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. <br> Use this when the content is complex, or you have non-textual content inside.

as-child
default:-
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.

as
default:-
AsTag | Component

The element or component this component should render as. Can be overwritten by `asChild`.

Event Emitted Value Type
select
[event: Event]
Slot Type
#default
any
#title
any
#text
any
#end
any

Radio group

Model Type
model-value
string

The value of the selected item in the group.

Prop Type
as-child
default:-
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.

as
default:-
AsTag | Component

The element or component this component should render as. Can be overwritten by `asChild`.

Slot Type
#default
any

Radio item

Prop Type
title
default:-
string

The title to display for the dropdown item.

text
default:-
string

The text to display for the dropdown item.

variant
default:-
"default" | "primary" | "none" | "muted"

The hover color of the dropdown-item inner elements.

rounded
default:-
"none" | "md" | "sm" | "lg"

The radius of the dropdown-item.

bindings
default:{}
{ indicator?: DropdownMenuItemIndicatorProps; }

Optional bindings to pass to the inner components.

value
default:-
string

The unique value of the item.

disabled
default:-
boolean

When `true`, prevents the user from interacting with the item.

text-value
default:-
string

Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. <br> Use this when the content is complex, or you have non-textual content inside.

as-child
default:-
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.

as
default:-
AsTag | Component

The element or component this component should render as. Can be overwritten by `asChild`.

Event Emitted Value Type
select
[event: Event]
Slot Type
#default
any
#text
any
#end
any
Prop Type
as-child
default:-
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.

as
default:-
AsTag | Component

The element or component this component should render as. Can be overwritten by `asChild`.

Customization

Your can override the component default CSS variables in your main.css file.

css
@theme {
  /* Default dropdown menu variables */
  --color-portal-default-bg: var(--color-white);
  --color-portal-default-border: var(--color-muted-300);
  --color-portal-default-item-bg-active: var(--color-muted-100);
  --color-portal-default-item-text: var(--color-input-default-text);
  --color-portal-default-item-text-active: var(--color-primary-base);

  /* Muted dropdown menu variables */
  --color-portal-muted-bg: var(--color-muted-50);
  --color-portal-muted-border: var(--color-muted-300);
  --color-portal-muted-item-bg-active: var(--color-muted-200);
  --color-portal-muted-item-text: var(--color-input-muted-text);
  --color-portal-muted-item-text-active: var(--color-primary-base);
}

Examples

Variants

Use the variant prop to control the colors of the dropdown menu.

vue
<template>
  <BaseDropdown variant="primary" label="Primary dropdown">
    <BaseDropdownItem>Leads</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Reports</BaseDropdownItem>
    <BaseDropdownItem>
      Settings
      <template #end>
        <BaseKbd size="sm">
          <span class="text-xs font-mono">⌘</span>
        </BaseKbd>
        <BaseKbd size="sm">
          <span class="text-xs font-mono px-0.5">P</span>
        </BaseKbd>
      </template>
    </BaseDropdownItem>
  </BaseDropdown>
</template>

Nested elements

You can nest other dropdowns inside a dropdown item, as well as checkboxes and radio buttons.

vue
<script setup lang="ts">
const checkedOne = ref(false)
const checkedTwo = ref(false)
const selection = ref('first')
</script>

<template>
  <div class="flex w-full justify-start gap-8">
    <BaseDropdown label="Inner Submenus">
      <BaseDropdownLabel>Label</BaseDropdownLabel>
      <BaseDropdownSub>
        <template #title>
          Profile
        </template>
        <BaseDropdownLabel>Label</BaseDropdownLabel>
        <BaseDropdownItem>Profile</BaseDropdownItem>
        <BaseDropdownItem>General</BaseDropdownItem>
        <BaseDropdownItem>Billing</BaseDropdownItem>
        <BaseDropdownItem>Support</BaseDropdownItem>
      </BaseDropdownSub>
      <BaseDropdownItem>Projects</BaseDropdownItem>
      <BaseDropdownItem>Team</BaseDropdownItem>
      <BaseDropdownSub>
        <template #title>
          Settings
        </template>
        <BaseDropdownLabel>Label</BaseDropdownLabel>
        <BaseDropdownItem>General</BaseDropdownItem>
        <BaseDropdownItem>Users</BaseDropdownItem>
        <BaseDropdownItem>Permissions</BaseDropdownItem>
        <BaseDropdownItem>Security</BaseDropdownItem>
      </BaseDropdownSub>
    </BaseDropdown>

    <BaseDropdown label="Radio">
      <BaseDropdownRadioGroup v-model="selection">
        <BaseDropdownRadioItem value="first">
          First
          <template #end>
            <div class="flex gap-0.5">
              <BaseKbd variant="default" size="sm">
                alt
              </BaseKbd>
              <BaseKbd variant="default" size="sm">
                1
              </BaseKbd>
            </div>
          </template>
        </BaseDropdownRadioItem>
        <BaseDropdownRadioItem value="second">
          Second
          <template #end>
            <div class="flex gap-0.5">
              <BaseKbd variant="default" size="sm">
                alt
              </BaseKbd>
              <BaseKbd variant="default" size="sm">
                2
              </BaseKbd>
            </div>
          </template>
        </BaseDropdownRadioItem>
        <BaseDropdownRadioItem value="third">
          Third
          <template #end>
            <div class="flex gap-0.5">
              <BaseKbd variant="default" size="sm">
                alt
              </BaseKbd>
              <BaseKbd variant="default" size="sm">
                3
              </BaseKbd>
            </div>
          </template>
        </BaseDropdownRadioItem>
      </BaseDropdownRadioGroup>
    </BaseDropdown>

    <BaseDropdown label="Checkbox">
      <BaseDropdownCheckbox
        v-model="checkedOne"
        title="Profile"
      />
      <BaseDropdownCheckbox
        title="Projects"
        disabled
      />
      <BaseDropdownCheckbox
        v-model="checkedTwo"
        title="Team"
      />
    </BaseDropdown>
  </div>
</template>

Spacing

Use the spacing and arrow options to control the dropdown's position.

vue
<template>
  <BaseDropdown
    label="Default spacing"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
  </BaseDropdown>

  <BaseDropdown
    label="With top arrow"
    :bindings="{ content: { sideOffset: 0 } }"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
    <BaseDropdownArrow />
  </BaseDropdown>

  <BaseDropdown
    label="With more spacing"
    :bindings="{ content: { sideOffset: 10 } }"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
  </BaseDropdown>
</template>

Label and composition

Use the DropdownLabel component to add a label to the dropdown menu. Mix and match with different options to create a unique dropdown.

vue
<template>
  <BaseDropdown header-label="My Team" variant="button" label="Dropdown" orientation="start">
    <BaseDropdownItem to="#" title="Lana Jensen" text="Software Engineer" color="default" rounded="sm">
      <template #start>
        <BaseAvatar src="/img/avatars/4.svg" size="xs" />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem to="#" title="Shawn Miller" text="Product Manager" color="default" rounded="sm">
      <template #start>
        <BaseAvatar src="/img/avatars/3.svg" size="xs" />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem to="#" title="John Marynski" text="Sales Manager" color="default" rounded="sm">
      <template #start>
        <BaseAvatar src="/img/avatars/18.svg" size="xs" />
      </template>
    </BaseDropdownItem>
    <BaseDropdownSeparator />
    <BaseDropdownItem to="#" title="Garry Porter" text="CEO - Founder" color="default" rounded="sm">
      <template #start>
        <BaseAvatar src="/img/avatars/6.svg" size="xs" />
      </template>
    </BaseDropdownItem>
  </BaseDropdown>
</template>

Button slot

Use the #button slot to customize the dropdown button.

vue
<template>
  <BaseDropdown
    :bindings="{
      content: {
        sideOffset: 0,
      },
    }"
  >
    <template #button>
      <BaseButton
        variant="primary"
        size="icon-sm"
        rounded="full"
        class="group"
      >
        <Icon name="ph:plus" class="block text-base transition-transform group-data-[state=open]:rotate-45" />
      </BaseButton>
    </template>

    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>

    <BaseDropdownArrow :width="16" :height="8" />
  </BaseDropdown>
</template>

Content: align

Use the :bindings prop to control the dropdown's content alignment.

vue
<template>
  <BaseDropdown
    label="End align" :bindings="{
      content: {
        align: 'end',
        sideOffset: 5,
      },
    }"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
  </BaseDropdown>
</template>

Content: side

Use the :bindings prop to control the popping side of the dropdown menu.

vue
<template>
  <BaseDropdown
    label="End align" :bindings="{
      content: {
        align: 'end',
        sideOffset: 5,
      },
    }"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
  </BaseDropdown>
</template>

Icon

Use the #start slot to insert an icon inside a dropdown item.

vue
<template>
  <BaseDropdown label="Dropdown" rounded="md">
    <BaseDropdownItem
      title="Profile"
      text="View your profile"
      class="w-72"
    >
      <template #start>
        <Icon name="solar:user-rounded-linear" class="me-2 block text-[1.15rem]" />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem
      title="Projects"
      text="View your projects"
    >
      <template #start>
        <Icon name="solar:case-linear" class="me-2 block text-[1.15rem]" />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem
      title="Team"
      text="Manage your team"
    >
      <template #start>
        <Icon name="solar:widget-3-linear" class="me-2 block text-[1.15rem]" />
      </template>
    </BaseDropdownItem>
    <BaseDropdownSeparator />
    <BaseDropdownItem
      title="Settings"
      text="Set your preferences"
    >
      <template #start>
        <Icon name="solar:settings-linear" class="me-2 block text-[1.15rem]" />
      </template>
    </BaseDropdownItem>
  </BaseDropdown>
</template>

Avatar

Use the #start slot to insert an avatar inside a dropdown item.

vue
<template>
  <BaseDropdown label="Dropdown" rounded="md">
    <BaseDropdownItem
      title="Lana Jensen"
      text="Software Engineer"
      class="w-80"
    >
      <template #start>
        <BaseAvatar
          src="/img/people/36.jpg"
          size="xs"
        />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem
      title="Shawn Miller"
      text="Product Manager"
    >
      <template #start>
        <BaseAvatar
          src="/img/people/18.jpg"
          size="xs"
        />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem
      title="John Marynski"
      text="Sales Manager"
    >
      <template #start>
        <BaseAvatar
          src="/img/people/16.jpg"
          size="xs"
        />
      </template>
    </BaseDropdownItem>
    <BaseDropdownItem
      title="Garry Porter"
      text="CEO - Founder"
    >
      <template #start>
        <BaseAvatar
          src="/img/people/6.jpg"
          size="xs"
        />
      </template>
    </BaseDropdownItem>
  </BaseDropdown>
</template>

Portal mode disabled

By disabling the portal mode, the dropdown will be rendered inside the component.

vue
<template>
  <BaseDropdown
    label="Fixed position" :bindings="{
      portal: {
        disabled: true,
      },
      content: {
        positionStrategy: 'fixed',
      },
    }"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
  </BaseDropdown>
  <BaseDropdown
    label="Absolute position" :bindings="{
      portal: {
        disabled: true,
      },
      content: {
        positionStrategy: 'absolute',
      },
    }"
  >
    <BaseDropdownItem>Profile</BaseDropdownItem>
    <BaseDropdownItem>Projects</BaseDropdownItem>
    <BaseDropdownItem>Team</BaseDropdownItem>
    <BaseDropdownItem>Settings</BaseDropdownItem>
  </BaseDropdown>
</template>