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

@todovue/tv-search

v1.1.3

Published

TvSearch provides a fast, accessible, and fully customizable search interface for Vue 3 apps.

Downloads

162

Readme

TODOvue Search (TvSearch)

A fast, accessible, and fully customizable search interface component for Vue 3 applications. Provides an elegant modal search experience with keyboard shortcuts, real-time filtering, and complete style customization. Works seamlessly in Single Page Apps or Server-Side Rendered (SSR) environments (e.g. Nuxt 3).

npm npm downloads npm total downloads License Release Date Bundle Size Node Version Last Commit Stars

Demo: https://ui.todovue.blog/search


Table of Contents


Features

  • Keyboard-first UX: Open with Ctrl+K / Cmd+K, close with Esc
  • Real-time filtering: Search as you type with instant results
  • Modal interface: Clean overlay design that focuses user attention
  • Fully customizable: Override colors for body, input, button, and text
  • Accessible: Built with semantic HTML and keyboard navigation
  • Lightweight: Minimal dependencies, Vue 3 marked as peer dependency
  • SSR compatible: Works in Nuxt 3 and other SSR frameworks
  • Auto-focus: Input field receives focus automatically when opened
  • Click-away close: Modal closes when clicking outside the content area
  • Flexible results: Pass any array of searchable items with custom properties

Installation

Using npm:

npm install @todovue/tv-search

Using yarn:

yarn add @todovue/tv-search

Using pnpm:

pnpm add @todovue/tv-search

Quick Start (SPA)

Global registration (main.js / main.ts):

import { createApp } from 'vue'
import App from './App.vue'
import { TvSearch } from '@todovue/tv-search'
import '@todovue/tv-search/style.css' // import styles
import '@todovue/tv-button/style.css' // import styles

createApp(App)
  .use(TvSearch) // enables <TvSearch /> globally
  .mount('#app')

Local import inside a component:

<script setup>
import { ref } from 'vue'
import { TvSearch } from '@todovue/tv-search'
import '@todovue/tv-search/style.css' // import styles
import '@todovue/tv-button/style.css' // import styles

const results = ref([
  {
    id: 1,
    title: 'How to use Vue 3',
    description: 'Vue 3 is the latest version of Vue.js',
    url: 'https://todovue.com/blog/how-to-use-vue-3',
  },
  {
    id: 2,
    title: 'How to use Vite',
    description: 'Vite is a build tool for modern web development',
    url: 'https://todovue.com/blog/how-to-use-vite',
  },
  {
    id: 3,
    title: 'How to use Pinia',
    description: 'Pinia is a modern store for Vue 3',
    url: 'https://todovue.com/blog/how-to-use-pinia',
  },
])

function handleSearch(query) {
  console.log('Search query:', query)
  // Handle search logic here
}
</script>

<template>
  <tv-search
    placeholder="Search documentation..."
    titleButton="Search"
    :results="results"
    @search="handleSearch"
  />
</template>

Nuxt 3 / SSR Usage

Create a plugin file: plugins/tv-search.client.ts (client-only is recommended since it uses keyboard events):

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@todovue/tv-search/nuxt'
  ]
})

Then use anywhere in your Nuxt app:

<template>
  <tv-search
    placeholder="Search site..."
    titleButton="Search"
    :results="searchResults"
    @search="onSearch"
  />
</template>

<script setup>
const searchResults = ref([
  // your search results
])

function onSearch(query) {
  // handle search
}
</script>

Optional direct import (no plugin needed):

<script setup>
import { TvSearch } from '@todovue/tv-search'
</script>

Component Registration Options

| Approach | When to use | |------------------------------------------------------|----------------------------------------------------| | Global via app.use(TvSearch) | Design system / used across many pages | | Global via app.component('TvSearch', TvSearch) | Custom component name / multiple search components | | Local named import import TvSearch from '...' | Single page usage / code splitting | | Nuxt plugin .client.ts | SSR apps with client-side interactions |


Props

| Prop | Type | Default | Description | Required | |--------------|--------|---------|---------------------------------------------------------------------------------------|----------| | placeholder | String | "" | Placeholder text for the search input field | true | | titleButton | String | "" | Text displayed on the search button | true | | results | Array | [] | Array of searchable items (see Results Data Structure) | true | | customStyles | Object | {} | Custom color scheme for theming (see Customization) | false |

customStyles Object

Customize the appearance by passing a customStyles object with any of these properties:

| Property | Type | Default | Description | |-------------|--------|-------------|----------------------------------------------------------| | bgBody | String | "#0E131F" | Background color of the modal overlay (with 0.9 opacity) | | bgInput | String | "#B9C4DF" | Background color of the search input area | | bgButton | String | "#EF233C" | Background color of the search button | | colorButton | String | "#F4FAFF" | Text color of the search button |


Events

| Event | Payload Type | Description | |--------|--------------|-------------------------------------------------------------------------------------------------| | search | String | Emitted when search is triggered (Enter key or button click). Returns the trimmed search query. |

Example:

<tv-search
  placeholder="Search..."
  titleButton="Go"
  :results="items"
  @search="handleSearch"
/>

<script setup>
function handleSearch(query) {
  console.log('User searched for:', query)
  // Perform API call, route navigation, etc.
}
</script>

Keyboard Shortcuts

| Shortcut | Action | |------------------------|-----------------------------------| | Ctrl + K / Cmd + K | Open the search modal | | Escape | Close the search modal | | Enter | Execute search with current input | | Click outside modal | Close the search modal |


Customization (Styles / Theming)

You can override the default color scheme by passing a customStyles object:

<script setup>
import { ref } from 'vue'
import { TvSearch } from '@todovue/tv-search'

const customStyles = ref({
  bgBody: "#1e1d23",
  bgInput: "#8673a1",
  bgButton: "#80286e",
  colorButton: "#d7c9c9",
})

const results = ref([
  // your results
])
</script>

<template>
  <tv-search
    placeholder="Type to search..."
    titleButton="Search"
    :results="results"
    :customStyles="customStyles"
  />
</template>

Example Custom Themes

Dark Theme:

const darkTheme = {
  bgBody: "#0E131F",
  bgInput: "#1F2937",
  bgButton: "#3B82F6",
  colorButton: "#FFFFFF",
}

Light Theme:

const lightTheme = {
  bgBody: "#F9FAFB",
  bgInput: "#FFFFFF",
  bgButton: "#6366F1",
  colorButton: "#FFFFFF",
}

Brand Theme:

const brandTheme = {
  bgBody: "#0A4539",
  bgInput: "#284780",
  bgButton: "#80286E",
  colorButton: "#D5B7B7",
}

Results Data Structure

The results prop expects an array of objects with the following structure:

interface SearchResult {
  id: number | string;    // Unique identifier (required for :key)
  title: string;          // Displayed in search results (required)
  description?: string;   // Additional info (optional, not currently displayed)
  url?: string;           // Navigation target (optional, not currently used in component)
  [key: string]: any;     // Any additional custom properties
}

Example:

const results = [
  {
    id: 1,
    title: 'Getting Started with Vue 3',
    description: 'Learn the basics of Vue 3 composition API',
    url: '/docs/vue3-intro',
    category: 'Tutorial',
  },
  {
    id: 2,
    title: 'Understanding Reactivity',
    description: 'Deep dive into Vue reactivity system',
    url: '/docs/reactivity',
    category: 'Advanced',
  },
]

Note: The component currently filters results based on the title property matching the user input (case-insensitive). You can handle the @search event to implement custom search logic or navigation.


Accessibility

  • Keyboard navigation: Full support for Ctrl+K/Cmd+K to open, Esc to close, and Enter to search
  • Focus management: Input automatically receives focus when modal opens and is selected for immediate typing
  • Semantic HTML: Uses proper <button>, <input>, and modal structure
  • Click-away: Modal closes when clicking the overlay, providing intuitive UX

Recommendations:

  • Provide clear, descriptive placeholder text
  • Use meaningful titleButton text (e.g., "Search", "Find", "Go")
  • Ensure sufficient color contrast when using customStyles
  • Consider adding aria-label attributes for screen reader support in future versions

SSR Notes

  • Safe for SSR: No direct DOM access (window / document) during module initialization
  • Event listeners: Keyboard event listeners are registered in onMounted and cleaned up in onBeforeUnmount
  • Client-side only: Keyboard shortcuts require browser environment; use .client.ts plugin in Nuxt
  • Icons: SVG icons are loaded via Vite's import.meta.glob, which works in both SPA and SSR builds
  • CSS Import: Starting from version 1.0.4, styles are served as a separate CSS file (dist/tv-search.css) and must be explicitly imported:
    • For Vue/Vite SPA: import '@todovue/tv-search/style.css' in main.ts
    • For Nuxt 3/4: Add '@todovue/tv-search/style.css' to the css array in nuxt.config.ts

Roadmap

| Feature | Status | |------------------------------------------|-------------| | Support for result url navigation | Planned | | Display description in results | Planned | | Customizable search icon | Planned | | Multiple keyboard shortcut options | Considering | | Result categorization / grouping | Considering | | Highlight matching text in results | Considering | | Recent searches history | Considering | | Loading state indicator | Considering | | Pagination for large result sets | Considering | | Fuzzy search / advanced filtering | Considering | | Theming via CSS variables | Considering | | TypeScript type definitions improvement | Planned | | ARIA attributes enhancement | Planned |


Development

Clone the repository and install dependencies:

git clone https://github.com/TODOvue/tv-search.git
cd tv-search
yarn install

Run development server with demo playground:

yarn dev

Build the library:

yarn build

Build demo site:

yarn build:demo

The demo is served from Vite using index.html + src/demo examples.


Contributing

Contributions are welcome! Please read our Contributing Guidelines and Code of Conduct before submitting PRs.

How to contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Changelog

See CHANGELOG.md for release history and version changes.


License

MIT © TODOvue


Attributions

Crafted for the TODOvue component ecosystem