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

@qnx/vuetify

v0.8.10

Published

An extendable library of Vuetify form components & more.

Readme

@qnx/vuetify

Declarative Vuetify form, table, and list components that talk to your API for you.

npm version npm downloads license Vue 3 Vuetify 4

📖 Documentation · 🤖 MCP Server: npx @qnx/vuetify-mcp


🚀 Overview

@qnx/vuetify is a Vue 3 component library built on top of Vuetify that removes the repetitive plumbing behind data-driven UIs. Forms, server-side tables, and infinite lists handle their own validation, HTTP requests, error display, pagination, and request cancellation — so your templates stay declarative.

Built for Vue 3 teams using Vuetify who are tired of rewriting the same axios + loading-state + error-mapping boilerplate on every page.

Use it for:

  • 📝 Forms with schema validation and automatic server-error mapping
  • 📊 Server-side data tables with paging, sorting, and filtering
  • 📜 Infinite-scroll lists wired to a paginated endpoint
  • 🔗 Filter forms linked to a table or list by a shared id

✨ Features

  • Zero fetch boilerplate — set an action, the request lifecycle is managed for you
  • Automatic error mapping — server validation errors map straight to form fields
  • Race-condition safe — in-flight requests are cancelled on change and unmount
  • Server-side tables & lists — paging, sorting, and filtering built in
  • TypeScript-first — generics flow your item types into slots
  • Localizable — override every built-in UI string with one call
  • Tree-shakeable — sideEffects: false, import only what you use

🧱 Tech Stack

| Layer | Technology | | ---------------- | ------------------------------------------- | | Framework | Vue 3 | | UI | Vuetify 4 | | Validation | vee-validate 4 + Yup (optional) | | State | Pinia 3 | | HTTP | axios via @qnx/composables | | Language | TypeScript | | Rich text (opt)| TinyMCE |

⚡ Quick Start

Get a validated, API-connected form on screen in under 5 minutes.

Prerequisites

| Requirement | Version | | ----------- | -------------------------------- | | Node.js | ^18.13 · ^20.11 · >=22 | | Vue | ^3.5 | | Vuetify | ^4.1 |

1. Install

# npm
npm install @qnx/vuetify

# pnpm
pnpm add @qnx/vuetify

# yarn / bun
yarn add @qnx/vuetify
bun add @qnx/vuetify

Install the peer dependencies:

npm install vuetify@^4.1.0 pinia vee-validate axios @qnx/composables

2. Register

// main.ts
import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
import { createPinia } from 'pinia'
import VqVuetify from '@qnx/vuetify'
import App from './App.vue'

createApp(App)
  .use(createVuetify())
  .use(createPinia())
  .use(VqVuetify)        // globally registers all Vq* components
  .mount('#app')

Prefer explicit imports? Skip .use(VqVuetify) and import components directly: import { VqForm, VqTextField } from '@qnx/vuetify'.

3. Use

<script setup>
import { object, string } from 'yup'

const schema = object({
  email: string().required().email(),
  password: string().required()
})
</script>

<template>
  <VqForm id="login" action="auth/login" :validation-schema="schema">
    <VqTextField name="email" label="Email" />
    <VqTextField name="password" label="Password" type="password" />
    <VqSubmitBtn />
  </VqForm>
</template>

That's it — validation, submission, loading state, and server-error display are handled. Next, point requests at your API in Configuration.

📂 Project Structure

src/
├─ components/
│  ├─ Vuetify/      # VqForm, VqDataTable, VqList, field inputs…
│  ├─ Basic/        # VqSubmitBtn, snackbar message queue
│  └─ Tinymce/      # VqTextEditor (optional integration)
├─ composables/     # useVqForm, useVqDataTable, useVqList
├─ config/          # locale / i18n strings
├─ store/           # Pinia stores (form state, messages)
├─ types/           # shared TypeScript types
├─ integrations.ts  # opt-in entry for optional components
└─ index.ts         # public entry + Vue plugin

🔧 Configuration

Point requests at your API

Components send requests through the shared axios instance from @qnx/composables. Configure its base URL once at startup:

import axios from 'axios'
import { setAxiosInstance } from '@qnx/composables/axios'

setAxiosInstance(
  axios.create({
    baseURL: import.meta.env.VITE_API_URL, // e.g. https://api.example.com
    headers: { Accept: 'application/json' }
  })
)

Now a component action="users" resolves to GET {baseURL}/users.

Required plugins

@qnx/vuetify relies on Vuetify and Pinia being installed on the app (see Quick Start). Pinia backs internal form and message state.

Rich text editor (optional)

VqTextEditor ships from the optional /integrations entry and requires @tinymce/tinymce-vue. Set the asset base URL once (the editor loads {baseUrl}/{filesPath}, with filesPath defaulting to static/tinymce/tinymce.min.js):

import { setConfig } from '@qnx/vuetify/integrations'
import { VqTextEditor } from '@qnx/vuetify/integrations'

setConfig({ baseUrl: '/tinymce' })

📸 Demo

| Resource | Link | | ----------------- | --------------------------------------------------- | | 📖 Documentation | https://qnx-vuetify-docs.vercel.app/ | | 🎮 Live Examples | https://qnx-vuetify-sample.vercel.app/ (soon) |

🧪 Usage Examples

Form with validation

<script setup>
import { object, string } from 'yup'

const schema = object({
  name: string().required(),
  email: string().required().email()
})
const onSuccess = (res) => console.log(res)
</script>

<template>
  <VqForm
    id="create-user"
    action="user/create"
    method="POST"
    :validation-schema="schema"
    @submited-success="onSuccess"
  >
    <VqTextField name="name" label="Name" />
    <VqTextField name="email" label="Email" />
    <VqSubmitBtn />
  </VqForm>
</template>

Server-side data table

Pagination, sorting, filtering, request cancellation, and loading state — all internal:

<script setup lang="ts">
import { useVqDataTable, collectVqHeaders } from '@qnx/vuetify'

interface User { id: number; name: string; email: string }

const UsersTable = useVqDataTable<User>()
const headers = collectVqHeaders([
  { title: 'Name', key: 'name' },
  { title: 'Email', key: 'email' }
])
</script>

<template>
  <UsersTable id="users" action="users" :headers="headers">
    <template #item="{ item, index }">
      <tr>
        <VqSerialNo :index="index + 1" />
        <td>{{ item.name }}</td>
        <td>{{ item.email }}</td>
      </tr>
    </template>
  </UsersTable>
</template>

Infinite-scroll list

<template>
  <VqList id="posts" action="posts" :page-size="10">
    <template #default="{ items, loading, finished, loadMore }">
      <div v-for="post in items" :key="post.id">{{ post.title }}</div>
    </template>
    <template #load-more>
      <VqListLoadMoreBtn />
    </template>
  </VqList>
</template>

Filter + table pattern

A VqTableFilter and VqDataTable (or VqList) share an id; changing a filter reloads the data automatically. Each change sends a request and cancels the previous one — set filter-debounce (ms) on the table or list to wait for typing to pause:

<template>
  <VqTableFilter id="users">
    <VqTextField name="search" label="Search" />
  </VqTableFilter>

  <VqDataTable id="users" action="users" :headers="headers" :filter-debounce="300" />
</template>

Reloading after a change

useFormFilterRepository refreshes a table or list from anywhere, with or without a VqTableFilter. Its key is the list's id plus _filter. reload() keeps a table on its current page; reset() returns to the first page. Lists restart from the first page for both.

import { useFormFilterRepository } from '@qnx/vuetify'

const { reload, reset } = useFormFilterRepository('users_filter')

Snackbar messages

Mount VqMessageQueue once near your app root to show messages from useMessageInstance() and from VqDatatableItemAction:

<script setup>
import { useMessageInstance } from '@qnx/vuetify'

const message = useMessageInstance()
message.success('Saved')
</script>

<template>
  <VqMessageQueue />
</template>

📘 API Reference

Form Components

Use inside a VqForm / useVqForm wrapper — they bind to form state and display validation automatically.

| Component | Description | | ---------------- | --------------------------------------------------- | | VqForm | Form wrapper — submission, validation, server calls | | VqTextField | Text input bound to form state | | VqTextarea | Textarea bound to form state | | VqAutocomplete | Autocomplete/select, supports remote items | | VqCheckbox | Checkbox bound to form state | | VqDatePicker | Date picker bound to form state | | VqTimePicker | Time picker bound to form state | | VqColorPicker | Color picker bound to form state | | VqOtpInput | OTP input bound to form state | | VqFileInput | File input bound to form state | | VqFileUpload | File upload with upload handling | | VqSubmitBtn | Submit button reflecting form busy state |

Fields validate on submit. Once a field shows an error, it re-validates as its value changes, so the message clears when corrected.

VqDatePicker, VqTimePicker, and VqColorPicker render a read-only text field that opens the picker. id and placeholder go to the text field, and other attributes go to the picker; use field-props for anything else on the text field, e.g. :field-props="{ variant: 'outlined' }". Set type to open the picker in a dialog instead of a menu. Space or ArrowDown opens the picker from the keyboard; Enter still submits the form.

VqDatePicker values. Picking a date stores a Date at local midnight, which JSON serializes to the previous day anywhere east of Greenwich. Add date-only to store a YYYY-MM-DD string instead.

VqFileInput validation. By default the value is stored under the literal key name[file], so a schema must use that exact key: object({ 'avatar[file]': mixed().required() }). A schema on avatar or avatar.file never sees the value, so the form can't submit. For a schema on avatar, add raw-name, which stores the value at avatar and changes the submitted key from avatar[file] to avatar.

Event names. submited-* is the established spelling, so it's the one to listen for.

Props

| Prop | Type | Default | Description | | ------------------------ | ---------- | ----------- | ------------------------------------------------ | | id | string | — | Unique form identifier (required) | | action | string | — | API endpoint for submission (required) | | method | string | "POST" | HTTP method | | initialValues | object | undefined | Initial values — form resets when this changes | | validationSchema | object | undefined | Yup validation schema. It can be swapped later, but vee-validate ignores one first set after the form is created; change the form's key to recreate it | | valuesSchema | object | undefined | Maps nested response fields to flat form fields | | formData | boolean | false | Submit as multipart/form-data | | successResponseHandler | function | — | Custom success handler | | errorResponseHandler | function | — | Custom error handler |

Events

| Event | Payload | Emitted when | | ------------------------ | ------------- | ---------------------------------- | | submited-success | ApiResponse | Server responds successfully | | submited-error | ApiResponse | Server returns a validation error | | submited-client-error | vee-validate invalid-submit context | Client-side validation fails | | submited-request-error | AxiosError | Request fails with any other error (500s, network failures) |

Data Table Components

| Component | Description | | ----------------------- | -------------------------------------------------------- | | VqDataTable | Server-side table on Vuetify's VDataTableServer | | VqSerialNo | <td> with the row's serial number | | VqDatatableItemAction | Row action button with a confirmation dialog |

VqDatatableItemAction is a named export and is not registered by the plugin, so an app's own global component of that name keeps working: import { VqDatatableItemAction } from '@qnx/vuetify'.

VqDataTable

| Prop | Type | Default | Description | | -------------- | --------------- | --------------------------------- | --------------------------------- | | id | string | — | Identifier (required) | | action | string | — | Fetch endpoint (required) | | method | string | "GET" | HTTP method | | page | number | 1 | Initial page | | itemsPerPage | number | 10 | Rows per page | | sortBy | SortByValue[] | [{ key: "name", order: "asc" }] | Default sort. The default is sent even if there's no name column; pass [] to send no sort | | filterDebounce | number | 0 | Delay (ms) before a filter change refetches |

Changing page, itemsPerPage, sortBy, or action after mount refetches. Emits error when a fetch fails.

Requests send page, itemsPerPage, and sortBy. VqList sends page and page_size instead, so a shared endpoint has to accept both.

VqDatatableItemAction

| Prop | Type | Default | Description | | ------------- | -------- | --------------------------------- | ----------------------------------------- | | id | string | — | Table ID — reloads after action (req.) | | itemId | string \| number | "0" | Row ID, appended to action as a path | | action | string | "user/change-status" | API endpoint | | method | string | "PUT" | HTTP method | | title | string | locale.confirmTitle | Dialog title | | description | string | locale.confirmDeleteDescription | Dialog message | | icon | string | Delete icon | Icon name or SVG path | | tooltip | string | locale.changeStatusTooltip | Tooltip and accessible label |

List Components

| Component | Description | | ------------------- | -------------------------------------------------------- | | VqList | Infinite-scroll list integrating with VqTableFilter | | VqListLoadMoreBtn | Loads the next page — used inside VqList | | VqTableFilter | Filter form linked to a table/list by id |

VqList

| Prop | Type | Default | Description | | ---------- | -------- | ------- | ------------------------------------ | | id | string | — | Identifier (required) | | action | string | — | Fetch endpoint (required) | | method | string | "GET" | HTTP method | | pageSize | number | 10 | Items per page | | filterDebounce | number | 0 | Delay (ms) before a filter change refetches |

Slots: default and load-more both receive { items, loading, finished, loadMore }; other VList slots are forwarded. Without a default or load-more slot, VList renders items itself. Emits error when a fetch fails.

VqTableFilter

| Prop | Type | Default | Description | | ---- | -------- | ------- | ---------------------------------------------- | | id | string | — | Must match the paired table/list (required) |

Composables

| Composable | Returns | | ---------------------- | ----------------------------------------------------------------- | | useVqForm(options) | A form wrapper plus resetForm, values, errors, meta, setFieldValue, setValues, setErrors, validate | | useVqDataTable<T>() | A typed VqDataTable with inference for item slots | | useVqList<T>() | A typed VqList with inference for the default slot's items | | collectVqHeaders(h) | Prepends a # serial-number column to a headers array | | useFormFilterRepository(key) | reload() / reset() for the table or list with that key (<id>_filter) | | useMessageInstance() | success() / warning() / error() snackbar helpers |

import { useVqForm } from '@qnx/vuetify'
import { object, string } from 'yup'

const { wrapper: EditUser, resetForm } = useVqForm({
  formId: 'edit-user',
  validationSchema: object({ name: string().required() }),
  initialValues: { name: '' }
})

Localization

Override any built-in string ("Submit", "Load More", dialog labels…) with setVqLocale. It accepts a partial — omitted keys keep the English default. resetVqLocale() restores defaults.

import { setVqLocale } from '@qnx/vuetify'

setVqLocale({
  submit: 'Enviar',
  loadMore: 'Cargar más',
  confirmTitle: 'Confirmación',
  confirmDeleteDescription: '¿Eliminar este registro?',
  confirm: 'Confirmar',
  cancel: 'Cancelar',
  selectTime: 'Seleccionar hora',
  close: 'Cerrar',
  next: 'Siguiente'
})

🤖 MCP Server

AI assistants can query this library's docs through the @qnx/vuetify-mcp server.

| Tool | Description | | ------------------------ | ----------------------------------------------------- | | get_component_list | List all components grouped by category | | get_component_docs | Full docs for a component: props, events, examples | | get_composable_list | List all composables with descriptions | | get_composable_docs | Full docs for a composable | | get_installation_guide | Installation steps and peer dependencies | | get_usage_guide | Practical usage examples |

Supported clients: Claude Desktop · Claude Code · Cursor · Windsurf · Cline · Continue.dev · Codex CLI · ChatGPT Desktop

{
  "mcpServers": {
    "qnx-vuetify": {
      "command": "npx",
      "args": ["-y", "@qnx/vuetify-mcp"]
    }
  }
}

🤝 Contributing

Contributions are welcome! For major changes, open an issue first to discuss the direction.

git clone https://github.com/yatendra121/vq-vuetify.git
cd vq-vuetify
pnpm install
pnpm test:unit     # run the test suite
pnpm lint          # lint & autofix
pnpm build         # build the library

Please keep changes focused and update tests as appropriate.

📄 License

MIT © 2023–PRESENT Yatendra Kushwaha