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

vue-easy-select

v0.2.0

Published

Flexible select component for Vue 3 — composable primitives plus a ready-to-use opinionated select. Single/multiple, searchable, slot-driven, form-friendly.

Downloads

19

Readme

vue-easy-select

📖 Live demo & docs →

Flexible select component for Vue 3 — composable primitives (VueEasyWrapper, VueEasyControl, VueEasyOptions) plus an opinionated ready-to-use VueEasySelect. Supports single/multiple modes, searchable options (local & remote), custom slots for control/item/arrow, and mirrors a hidden native <select> for form compatibility.

Philosophy

Off-the-shelf select components are a dead end — they ship a visual design you didn't pick and a dropdown you can't reach into. vue-easy-select takes the opposite stance: minimum UI, maximum configurability.

  • No chrome by default. No opinionated borders, shadows, or containers around the primitives. You bring your own wrapper, bordered panel, scroll shadows — whatever fits your design system.
  • Every visible piece is a slot. Arrow, option item, selected state, search icon, empty state — all overridable. No fighting !important to change an icon.
  • State is shared via a provide/inject context, not pinned to a specific DOM layout. Put the control in a header, the options list in a drawer, or inside any third-party popper — they all stay in sync because they inject the same context.
  • Your popper, your rules. Use VueEasySelect for a self-contained select, or compose VueEasyWrapper + VueEasyControl + VueEasyOptions with floating-vue, Floating UI, or your own positioning — the primitives don't assume a popper exists.
  • Accessible by default. Keyboard navigation (Arrow/Enter/Space/Escape), ARIA combobox + listbox semantics, and a hidden native <select> for form submission come out of the box.

Install

npm install vue-easy-select

Peer dependency: vue ^3.3.6. Zero runtime dependencies of its own.

Footprint & runtime

  • Size: ~12 kB gzip / ~28 kB raw / 43.7 kB unpacked, single ESM entry, no transitive deps.
  • CSS auto-injection: a tiny SSR-safe IIFE appends a <style> tag at first import — no separate stylesheet to import, no FOUC, no CSS loader required. Works inside a bundler and in raw <script type="module"> setups.
  • SSR-safe: the injection is gated by typeof document !== 'undefined', so the bundle imports cleanly on the server. Vue components themselves render fine in SSR; styles attach on hydration.
  • Tree-shaking: ships as one ESM entry, so when you import only VueEasySelect, bundlers can drop unused named exports. The CSS injection is a single top-level side-effect and stays in.
  • TypeScript: full .d.ts bundled (dist/index.d.ts).

Usage

Register globally:

import { createApp } from 'vue'
import VueEasySelect from 'vue-easy-select'

createApp(App).use(VueEasySelect).mount('#app')

Or import the components you need:

import { VueEasySelect, VueEasyWrapper, VueEasyControl, VueEasyOptions } from 'vue-easy-select'

No separate CSS import is needed — styles are inlined into the bundle and injected on first import.

Basic

<template>
    <VueEasySelect
        v-model="value"
        :options="options"
        placeholder="Pick a city"
    />
</template>

<script setup>
import { ref } from 'vue'
const value = ref('')
const options = [
    { id: 'Berlin', name: 'Berlin' },
    { id: 'Tokyo', name: 'Tokyo' },
    { id: 'New York', name: 'New York' }
]
</script>

Pass name="..." if you need a hidden native <select> mirror for form submission. Otherwise omit it — no extra DOM is rendered.

Multiple + searchable

<VueEasySelect
    v-model="value"
    :options="options"
    :is-multiple="true"
    :is-searchable="true"
    search-placeholder="Search"
/>

Custom popper (floating-vue)

Use the primitives directly when you need your own positioning:

<VueEasyWrapper v-model="value" :options="options">
    <Dropdown auto-size="min">
        <template #default="{ shown }">
            <VueEasyControl>
                <template #arrow>{{ shown ? '⬆️' : '⬇️' }}</template>
            </VueEasyControl>
        </template>
        <template #popper="{ hide }">
            <VueEasyOptions @selected="hide" />
        </template>
    </Dropdown>
</VueEasyWrapper>

Props (componentProps)

| Prop | Type | Default | Description | | --- | --- | --- | --- | | name | string | '' | Name of the hidden native <select> mirror. When set, a hidden <select> is rendered for form submission and assistive tech. Leave empty if you don't need it (e.g. filters, standalone widgets). | | options | Array<any> | [] | Options — object array or plain string[] | | keyField | string | 'id' | Object field used as option value | | nameField | string | 'name' | Object field used as visible label | | disabledField | string | 'disabled' | Object field marking an option as disabled | | placeholder | string | '' | Placeholder when nothing is selected | | isDisabled | boolean | false | Disable the whole control | | isSearchable | boolean | false | Enable search input | | isClearable | boolean | false | Render a clear (×) button in the control when a value is selected | | isRemoteSearch | boolean | false | Don't filter options locally — consumer controls options | | searchValue | string | '' | v-model-able search value | | searchPlaceholder | string | '' | Placeholder for search input | | searchPosition | string | 'control' | Where to render the search input. One of 'control' or 'options'. |

Mode-specific

| Prop | Type | Default | Description | | --- | --- | --- | --- | | isMultiple | boolean | false | Switch to multiple mode — modelValue becomes Array | | isAllowEmpty | boolean | false | (single mode) Allow deselecting the current value by clicking it |

License

MIT