web-ui-vuetify について
web-ui-vuetifyは、Vue 3開発者向けのVuetify実践ガイドです。コンポーネントの設定やテーマなどのカスタマイズ層を説明し、レイアウト、データテーブル、フォーム、レスポンシブ表示のパターンを紹介します。
主な機能
- 01Vuetifyプラグインとテーマの設定
- 02テーマ・デフォルト値・SASSの調整
- 03スロットによるコンポーネントのカスタマイズ
- 04データテーブルの選択と設定
- 05フォームルールとバリデーション
- 06レスポンシブレイアウトと表示制御
活用シーン
- 01Vue 3アプリでのVuetify設定
- 02テーマ、ダークモード、既定値の調整
- 03データテーブルとフォーム検証の構築
- 04画面サイズに応じたコンポーネント表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill web-ui-vuetifyインストール後、Claude Code で/web-ui-vuetifyを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/core.mddata-tables.mdforms.mdlayout.md詳細
Vuetify のパターン
クイックガイド: Vuetify には、Material Design を実装したスタイル設定済みの Vue 3 コンポーネントが 80 種類ほど含まれており、単一の
createVuetify()呼び出しで設定できます。まず覚えるべきなのは、テーマ、デフォルト設定、SASS という 3 つのカスタマイズレイヤーがあり、それぞれ置き換え可能ではないという点です。プロパティを所有するレイヤーを通じてカスタマイズしてください。CSS の上書きを使いたくなる場合は、たいていレイヤーの選択を誤っています。Vuetify は全体を通してテンプレート駆動型です。名前付き スロットで内部のマークアップを置き換えられるため、ラッパーのdivが答えになることはほとんどありません。現在のメジャーバージョンは v3.x で、バリデーションにはuseRules、スコープ内での prop のカスケードにはv-defaults-providerを使用します。
詳細なリソース:
- examples/core.md — プラグインの設定、テーマ、デフォルト設定、SASS、ブループリント、アイコン、SSR
- examples/data-tables.md — ヘッダー、列スロット、サーバーサイド、仮想化、グループ化
- examples/forms.md —
v-form、ルール、useRules、入力コンポーネント - examples/layout.md —
v-app、アプリバー、ドロワー、グリッド、ダイアログ、スナックバー - reference.md — コンポーネントの表、ブレークポイント、密度とバリアントの値、アンチパターン
該当するパス
ビルドプラグインがインストールされているかどうかで、2 つのファイルに記述する内容が変わります。
vite-plugin-vuetifyまたはwebpack-plugin-vuetifyを使用する場合。 コンポーネントは自動的に解決され、ツリーシェイクされるため、手動でインポートする必要はなく、"vuetify/styles"も一切インポートしません。SASS 変数の上書きが可能なのはこのパスのみで、styles.configFileを通じて行います。examples/core.md を参照してください。- プラグインを使用しない場合。
vuetify/componentsとvuetify/directivesをインポートして登録し、エントリーファイルで"vuetify/styles"をインポートします。すべてが同梱されるため、バンドルにはすべてのコンポーネントが含まれます。
<critical_requirements>
Vuetify のコードを書く前に
プラグインを app.use(vuetify) で登録します。 すべてのコンポーネントはこのプラグインを通じて解決されるため、登録しないと Vue は <v-btn> を不明な要素として扱い、エラーを出す代わりに空のカスタムタグをレンダリングします。
アプリケーションを v-app で囲みます。 レイアウトコンポーネントが登録される座標系であり、アプリバーやドロワーが v-main を覆わずに内側へ配置されるのはこの仕組みによるものです。
繰り返し使うプロパティは、defaults または v-defaults-provider で一度だけ設定します。 各インスタンスで variant を再指定すると、呼び出し箇所ごとに判断をやり直すことになります。この2つの仕組みを使えば、スタイルシートなしでグローバルなケースとセクション単位のケースに対応できます。
CSS を使う前に、スロットでカスタマイズします。 コンポーネント内の要素にはそれぞれ名前付きスロットがあるため、要素を置き換えるには <template v-slot:…> を使います。バージョンアップで壊れる可能性のあるセレクターを使う必要はありません。
v-data-table のヘッダーはテンプレートの外で定義します。 テンプレート内の配列リテラルは親がレンダリングされるたびに新しい識別子を持つため、そのたびにテーブル全体が再レンダリングされます。
this.$vuetify ではなく、コンポーザブルを使います。 useTheme()、useDisplay()、useDate()、useLocale() は Composition API の機能です。インスタンスプロパティは Options API のものであり、<script setup> では使用できません。
</critical_requirements>
自動検出: vuetify、createVuetify、vuetify/styles、vuetify/blueprints、vuetify/settings、
vuetify/iconsets、vite-plugin-vuetify、webpack-plugin-vuetify、v-app、v-main、v-btn、v-card、
v-data-table、v-data-table-server、v-data-table-virtual、v-text-field、v-select、v-autocomplete、
v-dialog、v-navigation-drawer、v-app-bar、v-snackbar、v-form、v-defaults-provider、
v-theme-provider、useTheme、useDisplay、useDate、useRules、useLocale、mdi-、$vuetify
対象範囲:
- ライブラリの設定:テーマ、ブループリント、デフォルト値、アイコンセット、SSR
- 変更がどのカスタマイズ層に属するかの選択
- 同梱コンポーネントの組み合わせ:レイアウト、入力、データテーブル、オーバーレイ、フィードバック
- コンポーネント内部のスロットベースのカスタマイズ
rules配列とuseRulesによるフォーム検証- グリッドのプロパティと
useDisplayによるレスポンシブな動作
別の場所で扱う内容:
- Vue 自体:リアクティビティ、コンポーネントの作成、ライフサイクル、自分で記述するコンポーザブル
- ルーティング、およびナビゲーション項目のリンク先
- コンポーネント独自の状態を超えるアプリケーションの状態:コンポーネントは値を受け取り、変更を通知します
- データ取得。
v-data-table-serverはユーザーの要求内容を通知し、取得したデータをレンダリングします - 一般的な CSS の手法。Vuetify 独自の3つの層は対象ですが、それらを取り巻くスタイルシートの設計は対象外です
Vuetify は意図的に明確な方針を持っています。デザインシステムを組み立てるためのプリミティブの集合ではなく、すでに組み立てられたデザインシステムを調整して使うものです。その方針に逆らうことが、Vuetify で問題が起きる最大の原因です。
調整は3つの層で行います。適切な層を選ぶことが、スキルの大部分を占めます。
- テーマ — 色とダークモードを実行時に CSS カスタムプロパティへ解決します。すべてが自動的に継承され、テーマの切り替えはツリー全体にリアクティブに反映されます。
- デフォルト値 —
createVuetify()でグローバルに設定するか、v-defaults-providerでスコープを指定するプロパティ値です。あまり活用されていない層ですが、外観だけでなく動作も変更でき、CSS のスコープ指定のようにネストしてカスケードし、実行時のコストもかかりません。 - SASS — プロパティでは公開されていない項目、たとえばフォントファミリー、基本の角丸、要素の高さに使うコンパイル時の CSS 変数です。ビルド時に固定され、ビルドプラグインがある場合にのみ利用できます。
プロパティは、必ずいずれか1つの層に属します。スタイルシートで上書きしようとする場合、特に !important を使う場合は、たいてい一つ上の層でそのプロパティを設定できます。
<decision_framework>
カスタマイズするレイヤー
| 変更する内容 | レイヤー |
|---|---|
| 色、またはダークモード | createVuetify() の theme。useTheme() で読み取ります |
| すべての箇所でのデフォルト props | createVuetify() の defaults |
| ページ内の一部分でのデフォルト props | v-defaults-provider |
| 角丸、高さ、フォントなど、CSS レベルのもの | @use "vuetify/settings" による SASS 変数 |
| コンポーネント内の特定の要素 | 名前付きスロット |
| 複数のコンポーネントの配置 | 通常のテンプレート構成 |
テーブルコンポーネントの選択
Static rows, no interaction → v-table (a styled HTML table)
Sorting, filtering, paging locally → v-data-table
The server does the sorting/paging → v-data-table-server (separate component, not a prop)
Thousands of rows, no paging → v-data-table-virtual (height is required)
Rows grouped under headings → v-data-table with group-by
</decision_framework>
基本パターン
パターン 1:プラグインのセットアップ
1 つの createVuetify() 呼び出しで、テーマ、デフォルト値、アイコンセット、ロケールを設定し、すべてのコンポーネントがそこから読み取ります。
import { createVuetify } from "vuetify";
const vuetify = createVuetify({
theme: {
defaultTheme: "light",
themes: { light: { colors: { primary: "#1867C0" } } },
},
defaults: {
VBtn: { variant: "flat", rounded: "lg" },
VTextField: { variant: "outlined", density: "comfortable" },
},
});
createApp(App).use(vuetify).mount("#app");
ブループリント、SASS のオーバーライド、TypeScript の拡張、SSR、SVG アイコンセットについては、examples/core.md をご覧ください。
パターン 2:テーマとダークモード
テーマは CSS カスタムプロパティになるため、1 つを切り替えるだけで、独自の再レンダリングを行わずにすべてのコンポーネントがリアクティブに更新されます。
<script setup>
import { useTheme } from "vuetify";
const theme = useTheme();
function toggleTheme() {
theme.global.name.value = theme.global.current.value.dark ? "light" : "dark";
}
</script>
theme.global.name は ref です。.value を代入してください。色には CSS から rgb(var(--v-theme-primary)) としてアクセスすることもできます。
コード全文:examples/core.md
パターン 3:グローバルおよびスコープ付きデフォルト値
defaults は、コンポーネントの種類ごとに props の値を設定します。v-defaults-provider はサブツリーに対して同じ設定を行い、スコープ内の既存の値とマージします。
<v-defaults-provider
:defaults="{
VBtn: { color: 'secondary', variant: 'tonal' },
VCard: { elevation: 0, border: true },
}"
>
<v-card>
<v-btn>Tonal and secondary, with no props of its own</v-btn>
</v-card>
</v-defaults-provider>
インスタンスに明示的に指定した props は常にデフォルト値より優先されるため、これによって既存の値を上書きするのではなく、基本設定の範囲を絞り込めます。
コード全文:examples/core.md
パターン 4:スロットベースのカスタマイズ
内部の各要素には名前付きスロットがあります。スロットを置き換えても、コンポーネントの動作、アクセシビリティの設定、密度の処理は維持されます。これらはラッパーの div の外側からは扱えません。
<v-text-field label="Amount" type="number">
<template v-slot:prepend-inner>
<v-icon>mdi-currency-usd</v-icon>
</template>
</v-text-field>
コード全文:列ごとのスロットは examples/data-tables.md、アクティベーターおよび append スロットは examples/layout.md をご覧ください。
パターン 5:データテーブル
v-data-table は、並べ替え、ページ分割、検索、選択を処理します。列は、ヘッダーの key に一致する v-slot:item.<key> でカスタマイズします。
<script setup>
const headers = [
{ title: "Name", key: "name" },
{ title: "Status", key: "status" },
{ title: "Actions", key: "actions", sortable: false },
];
</script>
<template>
<v-data-table :items="items" :headers="headers" item-value="id">
<template v-slot:item.status="{ item }">
<v-chip
:color="item.status === 'active' ? 'success' : 'error'"
size="small"
>
{{ item.status }}
</v-chip>
</template>
</v-data-table>
</template>
コード全文:examples/data-tables.md
パターン 6:フォームの検証
ルールは、true またはエラー文字列を返す通常の関数です。useRules を使うと、よく使われるルールをすぐに利用できます。
<script setup>
import { useRules } from "vuetify/labs/rules";
const rules = useRules();
</script>
<template>
<v-form ref="form" validate-on="submit" @submit.prevent="onSubmit">
<v-text-field
v-model="email"
label="Email"
:rules="[rules.required(), rules.email()]"
/>
<v-btn type="submit" color="primary">Submit</v-btn>
</v-form>
</template>
validate-on はルールを実行するタイミングを決めます。"submit" にすると、ユーザーが入力を終えるまでフォームの検証を行いません。デフォルトでは、キー入力のたびに検証します。
コード全文:examples/forms.md
パターン 7:useDisplay によるレスポンシブ動作
グリッドの props はレスポンシブな レイアウト を扱います。useDisplay はレスポンシブな ロジック、つまりコンポーネントの幅ではなく、どのコンポーネントをレンダリングするかの判断を扱います。
<script setup>
import { useDisplay } from "vuetify";
const { mobile, mdAndUp } = useDisplay();
</script>
<template>
<v-navigation-drawer :permanent="mdAndUp" :temporary="!mdAndUp" />
<v-app-bar :density="mobile ? 'compact' : 'default'" />
</template>
コード全文:examples/layout.md
<red_flags>
注意すべき点
実行時に問題が発生します:
app.use(vuetify)がありません — Vue がコンポーネントを認識できず、説明するエラーも出ないまま、空のカスタム要素としてレンダリングされます- 手動インポートの方法で
import "vuetify/styles"がありません — すべてのコンポーネントがマウントされますが、スタイルは適用されません <script setup>内でthis.$vuetifyを使っています — そこにはコンポーネントインスタンスがありません。コンポーザブルを使ってくださいv-rowを親に持たないv-col、またはv-containerの外にあるv-row— グリッドは完全な入れ子構造に依存しているため、それがないとエラーなしに崩れますv-data-tableにヘッダーや列の配列をインラインで記述しています — 親がレンダリングされるたびに新しい参照が作られるため、テーブル全体が毎回再レンダリングされます- 独自実装のサーバー側ページングを使った
v-data-table—v-data-table-serverは別のコンポーネントであり、クライアント側のコンポーネントは渡されたページをページングします heightのないv-data-table-virtual— 仮想スクローラーは測定するビューポートがないため、何もレンダリングしません
意外な動作:
densityに指定できるのは"default"、"comfortable"、"compact"です — 数値ではありません- Vuetify のブレークポイントは一般的な CSS のものとは異なります。
mdは 768px ではなく 960px からです v-defaults-providerは上位のプロバイダーを置き換えるのではなく、値をマージします。最も内側の値が優先されますtheme.variationsはprimary-lighten-1、primary-darken-2などを自動生成します — 手動で宣言すると、生成されたセットがその値で上書きされます- ダイアログやドロワーに
v-ifを指定すると、閉じるのではなく破棄されるため、トランジションや内部状態が失われます。表示の切り替えにはv-modelを使います - SASS 変数のオーバーライドには
styles.configFileを指定したビルドプラグインが必要です — これがないとファイルはコンパイルされず、オーバーライドは何もせずに無視されます "on-primary"はプライマリーカラーの背景上で使うテキストカラーであり、プライマリーカラーで色付けされたテキストではありませんreturn-objectが設定されていない場合、v-selectとv-autocompleteはitem-valueをバインドするため、モデルには元のオブジェクトではなくキーが格納されます