@qnx/vuetify
| Install | |
|---|---|
npm install @qnx/vuetify |
|
| Latest Version: | 0.8.5 |
| Vue: | 1 · 2 · 3 |
| License: | MIT |
| Last Updated: | Jun 17, 2026 |
| Links: | GitHub · npm |
@qnx/vuetify
Declarative Vuetify form, table, and list components that talk to your API for you.
📖 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:
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, debounced 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 }">
<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:
<template>
<VqTableFilter id="users">
<VqTextField name="search" label="Search" />
</VqTableFilter>
<VqDataTable id="users" action="users" :headers="headers" />
</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 |
VqForm props & events
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 |
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 |
— | Client-side validation fails |
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 |
VqDataTable & VqDatatableItemAction props
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 |
VqDatatableItemAction
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
— | Table ID — reloads after action (req.) |
itemId |
string |
"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 |
mdiDelete |
MDI icon path |
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 & VqTableFilter props
VqList
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
— | Identifier (required) |
action |
string |
— | Fetch endpoint (required) |
pageSize |
number |
10 |
Items per page |
VqTableFilter
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
— | Must match the paired table/list (required) |
Composables
| Composable | Returns |
|---|---|
useVqForm(options) |
A form wrapper plus state helpers (resetForm, errors, values) |
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 |
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'
})
🤖 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
Related Packages
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.8.5 | * | MIT | |
| 0.8.1 | * | MIT | |
| 0.8.0 | * | MIT | |
| 0.7.20 | * | MIT | |
| 0.7.12 | * | MIT | |
| 0.7.10 | * | MIT | |
| 0.7.8 | * | MIT | |
| 0.7.7 | * | MIT | |
| 0.7.5 | * | MIT | |
| 0.7.2 | * | MIT | |
| 0.7.0 | * | MIT | |
| 0.6.32 | * | MIT | |
| 0.6.30 | * | MIT | |
| 0.6.26 | * | MIT | |
| 0.6.20 | * | MIT | |
| 0.6.14 | * | MIT | |
| 0.6.12 | * | MIT | |
| 0.6.10 | * | MIT | |
| 0.6.6 | * | MIT | |
| 0.6.5 | * | MIT | |
| 0.6.3 | * | MIT | |
| 0.6.2 | * | MIT | |
| 0.6.0 | * | MIT | |
| 0.5.97 | * | MIT | |
| 0.5.95 | * | MIT | |
| 0.5.92 | * | MIT | |
| 0.5.89 | * | MIT | |
| 0.5.87 | * | MIT | |
| 0.5.85 | * | MIT | |
| 0.5.82 | * | MIT |
Showing the latest 30 of 54. See every release on npm