vuetify
Enforces style and architectural standards for Vuetify 4, including buttons, dialogs, and form validation.
Install
mkdir -p .claude/skills/vuetify && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18118" && unzip -o skill.zip -d .claude/skills/vuetify && rm skill.zipInstalls to .claude/skills/vuetify
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Esposter Vuetify 4 conventions — StyledButton for primary actions, @click navigateTo navigation (Vuetify :to lint-banned), v-prefixed auto-imported composables (useVDisplay/useVTheme), global defaults never repeated, v-btn tooltips, mergeProps for nested activators, typed SelectItemCategoryDefinition for selects/lists/menus (clearable banned), enum-value-as-display-title, dialog form validity (StyledFormDialog vs StyledEditFormDialog), StyledList, useVRules form validation, StyledAvatar, CSS custom properties over SASS variables, and scrollspy sub-nav. Apply when writing or reviewing Vuetify components, dialogs, selects, forms, or lists.Key capabilities
- →Apply StyledButton for primary actions
- →Implement navigation via navigateTo
- →Use v-prefixed auto-imported composables
- →Manage nested activators with mergeProps
- →Standardize dialog form validity
How it works
The skill enforces architectural patterns and naming conventions for Vuetify 4 components, including specific button styling and navigation handling.
Inputs & outputs
When to use vuetify
- →Reviewing Vuetify component implementation
- →Standardizing dialog forms and list layouts
- →Implementing consistent button styling and navigation
About this skill
Vuetify Conventions
Primary Buttons
Use StyledButton for every confirm / complete / primary call-to-action button (create, save, accept, publish, request, start). Never use a raw color="primary" v-btn — the global VBtn default has a transparent background, so a primary-coloured button reads badly on the app's transparent / v-main base; StyledButton renders the midnight-bloom gradient + white text instead.
- Pass Vuetify props through
:button-props="{ ... }"(camelCase — e.g.{ prependIcon: 'mdi-plus', disabled: !isValid, loading: isSubmitting }). For navigation put:to="RoutePath.X"on the<StyledButton>(it falls through to the rootv-btn) — never atoinsidebuttonProps. typeis a native attribute, not a typedVBtnprop — puttype="submit"directly on<StyledButton>(it falls through to the rootv-btn), never insidebuttonProps(which fails typecheck).@clickand other native listeners also fall through to the rootv-btn.- Destructive confirms stay a
color="error"v-btn(error red is visible on the transparent base) —StyledButtonis for positive/primary actions only.
StyledTooltipIconButton shape — isIconButton
Vuetify's icon prop on v-btn doesn't just place an icon — it switches the button to the icon-button variant: circular, equal width/height, no min-width. StyledTooltipIconButton passes :icon by default, so converting a regular <v-tooltip> + <v-btn> (icon as a <v-icon> child, rectangular shape) to it silently turns the button into a circle. When the rectangular default-button shape is intended, pass :is-icon-button="false" — the component then renders a regular v-btn with the icon as a child. rounded/tile in buttonProps cannot restore the rectangle (they only change corners, not the forced square dimensions).
Navigation — :to for Plain Links, @click="navigateTo(...)" for Logic-Then-Navigate
Vuetify components (v-btn, v-card, v-list-item, v-tab, v-chip, StyledButton, …) with a plain destination take :to directly — it renders a real anchor, so cmd/ctrl/middle-click open-in-new-tab works. Use an @click="navigateTo(...)" handler only when the action runs logic before navigating or computes the target at click time:
- For wrapper components put
:to/@clickdirectly on the wrapper —StyledButton/StyledTooltipIconButtonfall them through to the rootv-btn. Never passtoinside:button-props. - Route targets always come from
RoutePath(@esposter/shared), never string-built.
See the routing skill, which owns link choice, the raw-<a> ban, and imperative navigation.
Auto-Imported Composables — v Prefix
Vuetify composables are auto-imported with a v prefix. Never import from "vuetify" directly — they are globally available:
// auto-imported with v prefix — never import { useDisplay } from "vuetify"
const { smAndDown } = useVDisplay();
Common: useVDisplay(), useVTheme(), useVLocale(), useVDate().
Global Defaults (vuetify.config.ts)
These variants are set globally and must never be repeated on individual components:
| Component | Default |
|---|---|
VAutocomplete | variant="outlined" |
VColorInput | variant="outlined" |
VCombobox | variant="outlined" |
VFileInput | variant="outlined" |
VSelect | variant="outlined" |
VTextarea | variant="outlined" |
VTextField | variant="outlined" |
VBtn | flat, transparent background |
VDialog | maxWidth="100%", width=500 |
VTooltip | location="top" |
Button Conventions
- Every icon-only
v-btnmust have av-tooltip— wrap withv-tooltip+ descriptivetextso the action is discoverable. A button with visible label text (text="Remove"or default-slot text) is self-describing and does not need a tooltip. #activatorslot always first inv-tooltip(andv-menu).- Icon choice for create actions — use the semantically specific MDI icon when available:
mdi-table-row-plus-after(add rows),mdi-table-column-plus-after(add columns). Fall back tomdi-plusfor generic create.
<v-tooltip text="Descriptive action">
<template #activator="{ props: tooltipProps }">
<v-btn icon="mdi-some-icon" size="small" tile :="tooltipProps" @click="doSomething()" />
</template>
</v-tooltip>
Nested Activators — mergeProps, Never Stacked v-bind
When one button is the activator for multiple overlays (a v-menu/v-dialog/v-hover and a v-tooltip), each overlay's #activator slot hands you its own props object. Combine them with mergeProps(...) from vue on a single := — never stack two := binds (:="menuProps" :="tooltipProps"). A second v-bind of the same key silently overrides the first, so the loser's onClick / onMouseenter / class is dropped; mergeProps chains event handlers and concatenates class/style instead.
Order: structural/outer activator(s) first, tooltip last — e.g. mergeProps(menuProps, tooltipProps), mergeProps(dialogProps, tooltipProps), mergeProps(hoverProps, tooltipProps), or three-way mergeProps(tooltipActivatorProps, hoverProps, buttonProps).
<v-menu>
<template #activator="{ props: menuProps }">
<v-tooltip text="Options">
<template #activator="{ props: tooltipProps }">
<v-btn icon="mdi-dots-vertical" :="mergeProps(menuProps, tooltipProps)" />
</template>
</v-tooltip>
</template>
</v-menu>
A custom dialog/menu button that exposes an #activator slot should merge its own tooltip into the slot props so consumers don't have to:
<v-dialog>
<template #activator="{ props: dialogProps }">
<v-tooltip text="Settings">
<template #activator="{ props: tooltipProps }">
<slot name="activator" :="mergeProps(dialogProps, tooltipProps)" />
</template>
</v-tooltip>
</template>
</v-dialog>
Consumers then bind the slot scope directly (:="activatorProps") — do not wrap such an activator in a second v-tooltip; it already has one.
Icon Buttons Inside Input Slots
When placing a v-btn inside a v-text-field slot (e.g. #append-inner), use variant="plain" and omit color. The global VBtn default sets style: { backgroundColor: "transparent" } inline, which variant="flat" + color="primary" cannot override. variant="plain" works with the transparent default and lets the icon inherit the surrounding text color.
<!-- CORRECT — plain variant works with the transparent default -->
<v-tooltip text="Add item">
<template #activator="{ props: tooltipProps }">
<v-btn icon="mdi-plus" variant="plain" :="tooltipProps" @click="submit()" />
</template>
</v-tooltip>
Vuetify Selects and List Items
-
v-list-itemicon placement —prepend-iconfor decorative/category icons (before the title);append-iconfor action/severity icons (after, e.g. moderation actions). Action icon color/value come from the relevantAdminAction*Mapconstants — never hardcode inline. -
Type items as
SelectItemCategoryDefinition<T>[]({ title: string, value: T }) from@/models/vuetify/SelectItemCategoryDefinitionforv-autocomplete/v-select/v-list-item. Never inline untyped{ title, value }arrays — extract to a typed constant. -
Never specify
item-title/item-value— Vuetify defaults ("title","value") matchSelectItemCategoryDefinition. If source data has different field names, map it to{ title, value }at the call site — never pass the raw shape and compensate withitem-title/item-value.// CORRECT — map to SelectItemCategoryDefinition<T> so no extra props needed const categoryItems = computed<SelectItemCategoryDefinition<string>[]>(() => [ { title: "None", value: "" }, ...categories.value.map(({ id, name }) => ({ title: name, value: id })), ]); // <v-select :items="categoryItems" /> -
clearableis BANNED on selects — clearing emitsnull, which violates the no-null convention and fails non-nullable API inputs. Model "no selection / all" as an explicit first item carrying the empty sentinel ({ title: "All members", value: "" },{ title: "No limit", value: 0 }) so the ref stays a plain inferredref("")/ref(0)and the sentinel propagates end-to-end (see the typescript skill's sentinel section). -
Name the items constant to reflect what the value represents — e.g.
columnIdsforSelectItemCategoryDefinition<string>[]where each value is a column ID. -
Prefer enum values as display titles — set
titleto the enum member itself (title: SomeEnum.Foo) so key and value stay the same string. Update enum string values to match the intended label when reasonable, rather than inventing a separate title.Pick the construction by what each item carries:
Shape Construction Canonical example Enum value as title + extra fields (icon) as const satisfies Record<Enum, …>map +parseDictionaryToArray(Map, "value")DataSourceTypeItemCategoryDefinitionsCustom titles / an empty-sentinel item plain SelectItemCategoryDefinition<T>[]array literalBooleanFilterValueItemCategoryDefinitionsEnum value needing display formatting Object.values(Enum).map(...)throughprettify()`StringTransformationItemCategoryDefin
Content truncated.
When not to use it
- →Never use raw color='primary' v-btn
- →Never use :to for router navigation
- →Never stack multiple v-binds for activators
Prerequisites
Limitations
- →Bans :to for router navigation
- →Requires specific activator slot ordering
- →Requires StyledButton for primary actions
How it compares
This approach mandates global defaults and specific composable usage to prevent inconsistent component behavior across the application.
Compared to similar skills
vuetify side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| vuetify (this skill) | 0 | 10d | No flags | Intermediate |
| scroll-experience | 101 | 6mo | No flags | Intermediate |
| anthropic-frontend-design | 12 | 6mo | No flags | Intermediate |
| infographic-structure-creator | 1 | 5mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by Esposter
View all by Esposter →You might also like
scroll-experience
davila7
Expert in building immersive scroll-driven experiences - parallax storytelling, scroll animations, interactive narratives, and cinematic web experiences. Like NY Times interactives, Apple product pages, and award-winning web experiences. Makes websites feel like experiences, not just pages. Use when: scroll animation, parallax, scroll storytelling, interactive story, cinematic website.
anthropic-frontend-design
chaibuilder
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
infographic-structure-creator
antvis
Generate or update infographic Structure components for this repo (TypeScript/TSX in src/designs/structures). Use when asked to design, implement, or modify structure layouts (list/compare/sequence/hierarchy/relation/geo/chart), including layout logic, component composition, and registration.
logo-with-variants
crafter-station
Create logo components with multiple variants (icon, wordmark, logo) and light/dark modes. Use when the user provides logo SVG files and wants to create a variant-based logo component following the Clerk pattern in the Elements project.
design-context
WellApp-ai
Refresh UI/UX context from design system, Storybook, and codebase
threejs-postprocessing
CloudAI-X
Three.js post-processing - EffectComposer, bloom, DOF, screen effects. Use when adding visual effects, color grading, blur, glow, or creating custom screen-space shaders.