@phila/phila-ui-menu
v0.1.0
Published
Dropdown menu component for selecting one or multiple values.
Downloads
262
Readme
Menu Component
Accessible dropdown menu component for single-select, multi-select, and filterable (combobox) use cases. Built with full keyboard navigation and ARIA support.
Installation
pnpm add @phila/phila-ui-menuUsage
Single select
<script setup lang="ts">
import { Menu } from "@phila/phila-ui-menu";
import { ref } from "vue";
const selected = ref<string>();
const choices = [
{ text: "Active", value: "active" },
{ text: "Inactive", value: "inactive" },
{ text: "Pending", value: "pending" },
];
</script>
<template>
<Menu label="Status" :choices="choices" v-model="selected" />
</template>Multi-select
Pass multiple to allow more than one selection. modelValue becomes an array.
<script setup lang="ts">
import { Menu } from "@phila/phila-ui-menu";
import { ref } from "vue";
const selected = ref<string[]>([]);
const choices = [
{ text: "Parks", value: "parks" },
{ text: "Libraries", value: "libraries" },
{ text: "Recreation Centers", value: "rec" },
];
</script>
<template>
<Menu label="Departments" :choices="choices" v-model="selected" multiple />
</template>Filterable (combobox)
Pass filterable to render a text input that filters the option list as the user types.
<script setup lang="ts">
import { Menu } from "@phila/phila-ui-menu";
import { ref } from "vue";
const selected = ref<string>();
const choices = [
{ text: "Center City", value: "center-city" },
{ text: "Kensington", value: "kensington" },
{ text: "West Philadelphia", value: "west-phila" },
// ...
];
</script>
<template>
<Menu label="Neighborhood" :choices="choices" v-model="selected" filterable />
</template>With validation state
<template>
<Menu
label="Status"
:choices="choices"
v-model="selected"
supporting-text="Required for submission."
:error="errors.status"
required
/>
</template>Props
| Prop | Type | Default | Description |
| ---------------- | -------------------- | ------- | ---------------------------------------------------------------------------- |
| choices | MenuChoice[] | — | Array of options to display |
| modelValue | T \| T[] | — | Selected value(s); use with v-model |
| multiple | boolean | false | Enables multi-select mode; modelValue becomes an array |
| label | string | "" | Label displayed above the trigger |
| placeholder | string | "" | Placeholder text shown when nothing is selected |
| filterable | boolean | false | Renders a text input in the trigger for filtering options |
| required | boolean | false | Marks the field as required; hides the clear button |
| disabled | boolean | — | Disables the entire component |
| supportingText | string | "" | Helper text shown below the field |
| error | string \| string[] | [] | Error message(s); first item is displayed below the field with an error icon |
| className | string | "" | Additional CSS classes applied to the trigger field |
MenuChoice<T>
interface MenuChoice<T extends string | number | boolean = string | number | boolean> {
text: string; // Display label
value: T; // Underlying value bound to modelValue
}Events
| Event | Payload | Description |
| ------------------- | ---------- | ---------------------------------- |
| update:modelValue | T \| T[] | Emitted when the selection changes |
Keyboard Navigation
| Key | Behavior |
| ----------- | ----------------------------------------------------------- |
| Enter | Opens dropdown (non-filterable); selects highlighted option |
| Space | Opens dropdown (non-filterable); selects highlighted option |
| ArrowDown | Opens dropdown; moves highlight down (wraps) |
| ArrowUp | Opens dropdown; moves highlight up (wraps) |
| Home | Moves highlight to first option |
| End | Moves highlight to last option |
| Escape | Closes dropdown and returns focus to trigger |
Sub-components
These components are used internally by Menu and are not intended to be used directly. They are documented here for contributors.
MenuField
The trigger element rendered inside the combobox. In filterable mode it renders a native <input>; in standard mode it renders a styled span with the selected text.
- Emits
clearwhen the clear button is clicked. - Exposes
focus()andblur()so the parent can manage focus programmatically.
MenuDropdown
The role="listbox" container that appears below the trigger when the menu is open. Renders a MenuOption for each entry in filteredChoices and shows a "No results found" message when the filtered list is empty.
MenuOption
A single role="option" row inside the dropdown. Highlights on keyboard navigation, shows a CheckboxIcon in multi-select mode, and emits select on click.
Visual States
| State | Description | | -------- | ----------------------------------------------------- | | Default | Subtle inset border, white background | | Filled | Stronger inset border indicating a value is selected | | Open | Primary-colored border (2px), dropdown visible | | Focus | Primary-colored border (2px) | | Error | Error-colored border (2px), error message shown below | | Disabled | Muted border and text, not interactive |
