npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@phila/phila-ui-menu

v0.1.0

Published

Dropdown menu component for selecting one or multiple values.

Downloads

262

Readme

Menu Component

Status: In Progress

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-menu

Usage

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 clear when the clear button is clicked.
  • Exposes focus() and blur() 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 |