- 技術 💻
Vuetifyとは・使い方|v4の導入からフォーム・一覧・テーマまで実測
結論
Vuetify(ビューティファイ)は、Vue 3 の上で Material Design の部品(ボタン・フォーム・表・ダイアログなど)を <v-btn> のようなタグで並べて画面を作る UI コンポーネント集です。2026年10月29日時点の最新は 4.3.1 で、Vite のプラグインを使うと「使った部品だけ」がビルドに入ります。
この記事でわかること
- Vite+Vue 3 に Vuetify 4 を入れて、骨組み・ボタン・フォーム・一覧・ダイアログ・ダークテーマを動かした画面と計測値
- 全部登録・使った部品だけ・SVG アイコンの3通りでビルドしたサイズと、ブラウザが実際に受け取ったバイト数
- v-app が無い・アイコンが出ない・Vuetify 2 の書き方・SASS 未導入のエラー原文と直し方、他ライブラリとの判断表
Vue は「データが変わったら画面を描き直す」仕組みを持つ土台で、Vuetify はその上に乗る部品箱です。ボタンの見た目や表の並べ替えを自分で CSS と JavaScript で作る代わりに、Vuetify の部品を置いて属性で調整します。
flowchart TD
A[Vue 3<br>データと描画の土台] --> B[Vuetify 4<br>部品箱 105種]
B --> C[v-app / v-btn / v-form<br>v-data-table / v-dialog]
C --> D[自分の画面<br>テーマ色・密度・幅で調整]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| vuetify とは | Vue 3 用の Material Design の UI コンポーネント集(MIT ライセンス) | Vuetifyとは |
| vuetify 使い方(入れ方) | npm i vuetify → createVuetify() を app.use()。新規なら npm create vuetify@latest |
インストールと初期設定 |
| 最初に書くもの | 一番外側に <v-app>。無いと画面が真っ白になる |
画面の骨組み |
| どの版を使うか | 新規は 4.x。3.x は 2027年7月27日まで LTS、2.x は終了済み | バージョンの選び方 |
| ダークモード | useTheme().change('dark')。v4 は既定が OS の設定に従う |
テーマ・密度・レスポンシブ |
| サイズを減らすには | vite-plugin-vuetify の autoImport と SVG アイコン。手元では 2.0MB → 0.76MB | ビルドサイズの実測 |
| アイコンが出ない | @mdi/font の CSS を読み込んでいない。エラーは出ず空白になる |
よくあるエラー |
| Element Plus 等との違い | 見た目の流儀(Material か否か)と部品数・周辺機能で選ぶ | 他の UI ライブラリとの違い |
確認環境:Ubuntu 24.04.5 LTS の上で、Node.js 22.23.4・npm 10.9.9 を使い、作業用フォルダーに Vite 8.3.5・@vitejs/plugin-vue 6.0.10・Vue 3.5.44・Vuetify 4.3.1・vite-plugin-vuetify 2.1.3・@mdi/font 7.4.47・@mdi/js 7.4.47・sass-embedded 1.107.0 を npm で入れ、社員名簿(ボタン・登録フォーム・一覧・削除ダイアログ・テーマ切替)のサンプルを作りました。画面と計測値は Vite の開発サーバー(127.0.0.1:5173)と vite build の出力を Python の http.server で配信したものを、Chromium 153.0.8010.12(Playwright 1.63.0・日本語ロケール)で開いて取得しています。新規作成は create-vuetify 3.2.1 を対話なしで実行しました。版の日付・サポート期限・ブラウザ対応・v3 から v4 の変更点は Vuetify 公式ドキュメント(GitHub 上の原稿を含む)と npm のレジストリで確かめ、Nuxt と Vuetify 2 の書き方は公式ドキュメントの範囲で書いています。図は mermaid で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Vuetifyとは・使い方|v4の導入からフォーム・一覧・テーマまで実測」
Vuetifyとは(Vue の UI コンポーネント集)
この節では、Vuetify が何をしてくれるもので、Vue との関係がどうなっているかが分かります。
Vuetify は、Google の Material Design に沿った見た目と動きを持つ部品を、Vue 3 のコンポーネントとして提供するライブラリです。 公式の FAQ は「Vuetify は Vue.js の上に作られたコンポーネント集であり、Vue.js は UI を作るための JavaScript フレームワーク」と両者を分けて説明しています。ライセンスは MIT で、無料で商用にも使えます。
手元で node_modules/vuetify/lib/components を数えると V で始まるフォルダーが 105 あり、VBtn・VForm・VDataTable・VDialog・VNavigationDrawer のほか、VCalendar・VDatePicker・VStepper・VColorPicker・VOtpInput まで入っています。開発中の部品(VCommandPalette・VMaskInput・VHeatmap など 15種)は vuetify/labs に分かれています。
何が楽になるか
- 見た目を作らなくてよい:ボタンの影・押したときの波紋・入力欄のラベルの浮き上がり・表の並べ替え矢印が最初から付いています。
- レイアウトが決まっている:アプリバー・左のメニュー・本文の位置関係を
v-appが計算します。手元では本文(v-main)の左の余白が、メニューの幅と同じ 256px に自動で設定されていました。 - テーマで一括変更:色の名前(primary など)を1か所で決めると、全部品に反映されます。ダークモードも1行で切り替わります。
- 日本語の文言が同梱:
vuetify/localeのjaを渡すと、表の「1ページあたりの件数」などが日本語になります。
Vuetifyのバージョンの選び方(v4・v3・v2 とサポート期限)
この節では、2026年10月29日時点でどの版を使うべきか、各版のサポート期限と必要な Vue の版が分かります。
新しく始めるなら 4.x です。 npm の latest タグは 4.3.1 を指し、3.x は v3-stable タグ(3.13.7)として残っています。公式の Long-term support ページの表は次のとおりです。
| 版 | 状態 | 公開日 | LTS 終了日 | 必要な Vue |
|---|---|---|---|---|
| Vuetify 4.x | Active(開発中) | 2026年2月23日 | (次の大きな版の後) | 3.5 以上 |
| Vuetify 3.x | Maintained(保守) | 2022年11月1日 | 2027年7月27日 | 3.0 以上 |
| Vuetify 2.7 | Archived(終了) | 2019年7月23日 | 2025年1月23日 | 2.x |
| Vuetify 1.5 | Archived(終了) | 2019年2月5日 | 2020年7月31日 | 2.x |
4.3.1 の package.json の peerDependencies は vue: ^3.5.0 || ^3.6.0-0 で、Vue 3.4 以前には入りません。対応ブラウザは公式の Browser support ページで Chromium 系 119 以上・Firefox 128 以上・Safari 16.4 以上で、Internet Explorer は非対応です。Chromium 99〜118 と Firefox 97〜127 は「一部対応」で、相対色構文(rgb(from …))が使えないため一部の色が正しく出ないと注記されています。
手元で npm の公開日を引くと、4.x は 4.0.0(2月23日)→ 4.1.0(6月2日)→ 4.2.0(9月2日)→ 4.3.0(10月19日)→ 4.3.1(10月26日)と、ほぼ月に1回以上の更新が続いています。3.x も 3.13.7(10月14日)まで修正が出ています。
Vuetifyの使い方(1)インストールと初期設定
この節では、Vite+Vue 3 のプロジェクトに Vuetify 4 を入れて最初の画面を出すまでの手順と、新規なら npm create vuetify で何ができるかが分かります。
既存の Vue 3 プロジェクトなら、パッケージを入れて createVuetify() を app.use() に渡すだけです。 使った部品だけをビルドに入れるため、vite-plugin-vuetify も一緒に入れます。
パッケージを入れる
npm install vuetify @mdi/font vite-plugin-vuetify。手元では Vuetify 4.3.1・@mdi/font 7.4.47・vite-plugin-vuetify 2.1.3 が入り、node_modules は 178MB になった(Vue・Vite 含む。後で入れた sass-embedded で 239MB)。
vite.config.js にプラグインを足す
vuetify({ autoImport: true }) を vue() の後ろに置く。公式は「Vue プラグインの後に Vuetify プラグインを置く」と明記している。
plugins/vuetify.js を作る
'vuetify/styles' とアイコンの CSS を読み込み、createVuetify({ ... }) でテーマ・ロケール・既定値を決めて export する。
main.js で登録する
createApp(App).use(vuetify).mount('#app')。use を忘れると「Could not find defaults instance」で止まる(よくあるエラーの節)。
App.vue の一番外側を v-app にする
<v-app><v-main>…</v-main></v-app>。npm run dev で 127.0.0.1:5173 を開く。手元では Vite が 984ms で起動した。
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vuetify from 'vite-plugin-vuetify'
export default defineConfig({
plugins: [
vue(),
vuetify({ autoImport: true }), // vue() の後ろに置く
],
})
// src/plugins/vuetify.js
import 'vuetify/styles'
import '@mdi/font/css/materialdesignicons.css'
import { createVuetify } from 'vuetify'
import { ja, en } from 'vuetify/locale'
export default createVuetify({
locale: { locale: 'ja', fallback: 'en', messages: { ja, en } },
theme: {
defaultTheme: 'light',
themes: {
light: { colors: { primary: '#1565C0', secondary: '#00897B' } },
dark: { colors: { primary: '#90CAF9', secondary: '#80CBC4' } },
},
},
defaults: {
VBtn: { variant: 'flat' },
VTextField: { variant: 'outlined', density: 'comfortable' },
},
})
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
createApp(App).use(vuetify).mount('#app')
defaults は部品ごとの既定値です。上の例では、全部の v-btn が variant="flat"、全部の v-text-field が枠線つきになります。手元の画面でも、variant を書いていないボタンの class に v-btn--variant-flat が付いていました。
新規なら create-vuetify
公式が推奨する新規作成は npm create vuetify@latest です。手元で create-vuetify 3.2.1 を対話なしで実行しました。
$ npm create vuetify@latest -- --name scaffold --platform vue --router router --css none --packageManager npm --no-typescript
T Create Vuetify v3.2.1
o Template downloaded
o Configuration applied
o Converted to JavaScript
— scaffold has been generated at scaffold
T-Next steps-----------------------------T
| cd scaffold |
| npm install |
| npm run dev |
—----------------------------------------—
生成された package.json の依存は vuetify ^4.0.2・vue ^3.5.30・vue-router ^5.0.3・@mdi/font 7.4.47・@fontsource/roboto・vite ^8.0.0・vite-plugin-vuetify ^2.1.3・sass-embedded・unplugin-fonts でした。src/plugins/vuetify.js は defaultTheme: 'system'、vite.config.mjs は autoImport: true と styles.configFile: 'src/styles/settings.scss' が設定され、AGENTS.md(AI コーディング支援向けの決まり)まで作られます。--help で見えた選択肢は次のとおりです。
| オプション | 選べる値 | 意味 |
|---|---|---|
--platform |
vue / nuxt | Vue 単体か Nuxt か |
--router |
router / file-router / none | vue-router の有無。file-router はファイル名でルートを作る |
--features |
pinia, eslint, i18n, mcp | 状態管理・静的検査・多言語・Vuetify MCP |
--css |
unocss / tailwindcss / none 等 | ユーティリティ CSS を併用するか |
--no-typescript |
— | 既定は TypeScript。JavaScript にする |
--preset |
Base / Full / Vuetify0 | 組み合わせの雛形 |
Vue 自体のプロジェクト作成(create-vue)とフォルダー構成は、関連記事「Vue環境構築|create-vueでプロジェクト作成とディレクトリ構成」で扱っています。vite.config の書き方は、関連記事「vite.configの書き方|用途別コピペ一覧とVite 8の変更点」にまとめています。
Vuetifyの使い方(2)画面の骨組み:v-app・v-app-bar・v-navigation-drawer・v-main
この節では、アプリバー・左メニュー・本文の骨組みをどう書き、Vuetify がどう位置を計算しているかが分かります。
v-app が一番外側、v-main が本文で、v-app-bar と v-navigation-drawer はその間に置きます。 本文の余白は Vuetify が自動で計算します。
<template>
<v-app>
<v-app-bar color="primary" density="compact">
<v-app-bar-nav-icon @click="drawer = !drawer" />
<v-app-bar-title>社員名簿(Vuetify 4 サンプル)</v-app-bar-title>
<v-btn icon="mdi-theme-light-dark" @click="toggleTheme" aria-label="テーマ切替" />
</v-app-bar>
<v-navigation-drawer v-model="drawer">
<v-list density="compact" nav>
<v-list-item prepend-icon="mdi-view-dashboard" title="ダッシュボード" value="home" />
<v-list-item prepend-icon="mdi-account-multiple" title="社員名簿" value="members" active />
<v-list-item prepend-icon="mdi-cog" title="設定" value="settings" />
</v-list>
</v-navigation-drawer>
<v-main>
<v-container>
ここに本文
</v-container>
</v-main>
</v-app>
</template>
Chromium で描画した結果を計測すると、次のようになっていました。
| 要素 | 計測した値 | 意味 |
|---|---|---|
.v-application の class |
v-theme--light v-layout v-layout--full-height v-locale--is-ltr |
テーマ名・レイアウト・文字方向が class で付く |
v-app-bar の背景色 |
rgb(21, 101, 192) |
テーマの primary(#1565C0)がそのまま使われる |
v-main の padding |
左 256px・上 48px | メニューの幅 256px と compact のアプリバーの高さ 48px を自動で確保 |
| フォント | Roboto, sans-serif |
Roboto は同梱されない。入れなければ sans-serif で表示 |
v-main には --v-layout-left: 256px のような CSS 変数が付き、メニューを閉じると 0px に変わります。この計算を担っているのが v-app(正確にはその中の layout)で、v-app の外に v-app-bar を置くと「Could not find injected layout」で止まります(よくあるエラーの節)。
フォントについて、公式は「既定のフォントは Roboto だが、自分で読み込む」と書いています。create-vuetify の雛形は @fontsource/roboto と unplugin-fonts で読み込む形になっていました。手元のサンプルは読み込んでいないため、日本語はシステムのゴシック体で表示されています。
Vuetifyの使い方(3)v-btn・v-form と入力検証
この節では、ボタンの6つの見た目と、フォームの入力検証(必須・メール形式・文字数)の書き方と、画面に出た文言が分かります。
ボタンは variant で見た目、color で色、density で高さを変えます。 同じ primary 色で6種類を並べ、Chromium で背景色と文字色を取りました。
| variant | 背景 | 文字色 | 見え方 |
|---|---|---|---|
| elevated(既定) | rgb(21, 101, 192) | 白 | 塗りつぶし+影。class に v-btn--elevated |
| flat | rgb(21, 101, 192) | 白 | 塗りつぶし、影なし |
| tonal | 透明+薄い色の重ね | primary | 淡い背景。背景は transparent で疑似要素が色を重ねる |
| outlined | 透明 | primary | 枠線だけ |
| text | 透明 | primary | 文字だけ。ホバーで薄く色が付く |
| plain | 透明 | primary(薄め) | 文字だけで、ホバーの背景も無い |
高さは density で変わり、default 36px・comfortable 28px・compact 24px でした。text-transform は none で、v4 では英字が自動で大文字になりません(v3 までは uppercase が既定。移行の節)。
<v-btn color="primary" variant="tonal">tonal</v-btn>
<v-btn color="primary" prepend-icon="mdi-plus">追加</v-btn>
<v-btn color="error" loading>loading</v-btn>
<v-btn disabled>disabled</v-btn>
<v-btn icon="mdi-delete" size="small" variant="text" color="error" aria-label="削除" />
v-form と rules
入力検証は、各入力部品の rules に「正しければ true、誤りなら文言の文字列」を返す関数を渡します。v-form の validate() が全部の部品をまとめて確かめます。
<v-form ref="form" @submit.prevent="submit">
<v-text-field v-model="name" label="氏名" :rules="[rules.required, rules.max20]" counter="20" />
<v-text-field v-model="email" label="メール" :rules="[rules.required, rules.email]" type="email" />
<v-select v-model="dept" :items="depts" label="部署" :rules="[rules.required]" />
<v-checkbox v-model="agree" label="内容を確認した" :rules="[v => !!v || '確認が必要です']" />
<v-btn type="submit" color="primary" prepend-icon="mdi-content-save">登録</v-btn>
</v-form>
const rules = {
required: v => !!v || '必須項目です',
email: v => /.+@.+\..+/.test(v) || 'メールアドレスの形式で入力します',
max20: v => (v || '').length <= 20 || '20文字以内で入力します',
}
async function submit() {
const { valid } = await form.value.validate()
if (!valid) return
items.value.push({ id: nextId(), name: name.value, dept: dept.value, email: email.value })
form.value.reset()
}
何も入力せずに「登録」を押すと、4つの部品に v-input--error が付き、.v-messages__message に次の文言が出ました。
必須項目です
必須項目です
必須項目です
確認が必要です
メール欄に「abc」と打つと、入力中に「メールアドレスの形式で入力します」に変わります。正しく入力して登録すると、一覧の下の件数表示が「1-5 件目 / 12件」から「1-5 件目 / 13件」になり、v-snackbar に「新井 太郎 を登録しました」と出ました。
v4 の組み込みルール(createRulesPlugin)
Vuetify 4 には '$required' のような名前で使える組み込みのルールがあります。使うには createRulesPlugin を登録します。
import { createVuetify, createRulesPlugin } from 'vuetify'
const vuetify = createVuetify({ locale: { locale: 'ja', messages: { ja, en } } })
app.use(vuetify).use(createRulesPlugin({}, vuetify.locale))
<v-text-field v-model="v" label="氏名" :rules="['$required', ['$maxLength', 5]]" />
<v-text-field v-model="m" label="メール" :rules="['$email']" />
手元で6文字と「abc」を入れると、ja ロケールの文言で次のように出ました。
最大5文字まで入力してください
有効なメールアドレスを入力してください
引数のあるルールは ['$maxLength', 5] のように配列で書きます。'$maxLength(5)' と文字列で書くと、ルールが undefined になり、コンソールに undefined is not a valid value. Rule functions must return boolean true or a string. が出て検証されませんでした。また、createRulesPlugin を登録し忘れると、エラーは出ずに画面に「$required」「$email」という文字がそのまま表示されました。
Vuetifyの使い方(4)v-data-table・v-dialog・v-snackbar
この節では、一覧表の並べ替え・検索・ページ分け、削除確認ダイアログ、通知の書き方と、動かして分かった注意点が分かります。
v-data-table は headers(列の定義)と items(行の配列)を渡すだけで、並べ替え・ページ分け・件数表示が付きます。 search を渡すと全列を対象に絞り込みます。
<v-text-field v-model="search" label="検索" prepend-inner-icon="mdi-magnify" clearable max-width="320" />
<v-data-table :headers="headers" :items="items" :search="search" :items-per-page="5">
<template #item.dept="{ value }">
<v-chip size="small" :color="value === '開発部' ? 'primary' : 'secondary'">{{ value }}</v-chip>
</template>
<template #item.actions="{ item }">
<v-btn icon="mdi-delete" size="small" variant="text" color="error" @click="askDelete(item)" />
</template>
</v-data-table>
const headers = [
{ title: 'ID', key: 'id', align: 'end' },
{ title: '氏名', key: 'name' },
{ title: '部署', key: 'dept' },
{ title: 'メール', key: 'email' },
{ title: '操作', key: 'actions', sortable: false },
]
12人分のデータで動かした結果です。
| 操作 | 結果(Chromium で取得) |
|---|---|
| 初期表示 | 5行表示。下に「1ページあたりの件数:5」「1-5 件目 / 12件」(ja ロケールの文言) |
| 「氏名」の見出しを1回押す | aria-sort="ascending" が付き、伊藤→加藤→吉田→高橋→佐藤 の順 |
| もう1回押す | 降順。鈴木→渡辺→田中→中村→新井 |
| 検索欄に「営業」 | 営業部の5人だけになり「1-5 件目 / 5件」 |
| density を compact | 行の高さ 51.7px → 41px(comfortable は 44px) |
注意したいのは並べ替えの順です。 「伊藤→加藤→吉田→高橋→佐藤」は五十音順ではなく、漢字の文字コード順です。日本語の名前を五十音で並べたいときは、読み仮名の列(yomi など)をデータに持たせて、その列で並べ替えるか、headers の sort に Intl.Collator('ja') を使う比較関数を渡します。
const collator = new Intl.Collator('ja')
const headers = [
{ title: '氏名', key: 'name', sort: (a, b) => collator.compare(a, b) },
]
v-dialog(削除の確認)
<v-dialog v-model="dialog" max-width="400">
<v-card title="削除の確認" :text="`${target?.name} を一覧から削除します。`">
<v-card-actions>
<v-spacer />
<v-btn variant="text" @click="dialog = false">やめる</v-btn>
<v-btn color="error" @click="doDelete">削除する</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-snackbar v-model="snackbar" :timeout="2000">{{ snackText }}</v-snackbar>
ゴミ箱のボタンを押したときの状態を計測しました。
- ダイアログの要素に
role="dialog"とaria-modal="true"が付いていた。 - 背景(scrim)は黒・不透明度 0.32、ダイアログの
z-indexは 2400。 - フォーカスはダイアログの中身(
.v-overlay__content)へ移り、<html>にv-overlay-scroll-blockedが付いて背景のスクロールが止まった。 - Esc キーで閉じ、「削除する」を押すと一覧が「1-5 件目 / 12件」に減り、snackbar に「鈴木 花子 を削除しました」と出た。
テーマ(色・ダークモード)・密度・レスポンシブ
この節では、色の決め方、ダークモードの切り替え、画面幅で変わる動き(ブレークポイント)を実測値つきで説明します。
テーマは createVuetify({ theme }) で色を決め、useTheme() で切り替えます。 Vuetify 4 では defaultTheme の既定が 'system'(OS の設定に従う)に変わりました。
import { useTheme } from 'vuetify'
const theme = useTheme()
function toggleTheme() {
theme.change(theme.global.name.value === 'dark' ? 'light' : 'dark')
}
| 計測項目 | light | dark |
|---|---|---|
.v-application の class |
v-theme--light |
v-theme--dark |
| 背景色 | rgb(255, 255, 255) | rgb(18, 18, 18) |
CSS 変数 --v-theme-primary |
21,101,192(#1565C0) | 144,202,249(#90CAF9) |
| アプリバーの背景 | rgb(21, 101, 192) | rgb(144, 202, 249) |
color-scheme |
light | dark(スクロールバーも暗くなる) |
色は <style id="vuetify-theme-stylesheet">(手元では 13,192 文字)に CSS 変数として書き出され、切り替えると変数が入れ替わります。自分の CSS からも rgb(var(--v-theme-primary)) で参照できます。v4 ではテーマ色が透過に対応したため、rgba(var(--v-theme-primary), 0.8) の書き方は rgb(from rgb(var(--v-theme-primary)) r g b / 0.8) か color-mix() に変えるよう公式の移行ガイドに書かれています。
defaultTheme を書かずに起動した画面を、Chromium のダークモード設定(prefers-color-scheme: dark)で開くと v-theme--dark・背景 rgb(18, 18, 18) になり、ライト設定では白になりました。以前のように常にライトで出したいときは defaultTheme: 'light' を明示します。
密度(density)
density は default・comfortable・compact の3段階で、ボタン・入力欄・表・リストに共通です。社内の業務画面のように1画面に多くの情報を出すなら compact、スマホで指で押すなら default が向きます。手元の計測は、ボタン 36→28→24px、表の行 51.7→44→41px でした。
ブレークポイントと useDisplay
画面幅の区分(ブレークポイント)は v4 で Material Design 3 の値に変わりました。useDisplay() の name を表示しながら、Chromium の幅を変えて確かめた結果です。
| 幅(px) | name | v-container の幅 | 左メニュー |
|---|---|---|---|
| 1545 | xl | 1289(本文いっぱい) | 常時表示 |
| 1544 | lg | 1000(上限) | 常時表示 |
| 1145 | lg | 889 | 常時表示 |
| 1144 | md | 700(上限) | 隠れる(temporary) |
| 840 / 839 | md / sm | 700 / 839 | 隠れる |
| 600 / 599 | sm / xs | 600 / 599 | 隠れる |
境目は xs/sm が 600px、sm/md が 840px、md/lg が 1145px、lg/xl が 1545px でした。公式の移行ガイドにある v3 → v4 の変更(md 960→840、lg 1280→1145、xl 1920→1545、xxl 2560→2138)と一致します。v-navigation-drawer は lg 未満で自動的に「重ねて表示(temporary)」になり、v-main の左余白が 256px → 0px に変わりました。v-container の上限も md 700px・lg 1000px で、v3 の 900px・1200px より狭くなっています。
import { useDisplay } from 'vuetify'
const { mdAndUp, name, width } = useDisplay()
// mdAndUp.value が true なら 840px 以上
アイコンの使い方(@mdi/font と @mdi/js)
この節では、アイコンを出す2つの方法と、それぞれの大きさ・書き方の違いが分かります。
Vuetify 自体はアイコンを同梱していません。 公式のインストール手順も「アイコンを入れるのを忘れずに」と注意し、例として @mdi/font を挙げています。
アイコンの入れ方
icon="mdi-home" と名前で書く。手軽だが、使わない 7,000 個分も配信されるimport { mdiHome } from '@mdi/js' で SVG のパスを渡す。使ったアイコンだけがビルドに入り、フォントの読み込みが無い。書く量は増える手元の差:CSS 653KB → 330KB、フォント 403KB → 0
// @mdi/js を使う場合の plugins/vuetify.js
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'
import { mdiHome, mdiDelete } from '@mdi/js'
export default createVuetify({
icons: {
defaultSet: 'mdi',
aliases: { ...aliases, home: mdiHome, delete: mdiDelete },
sets: { mdi },
},
})
<!-- 名前で書く(@mdi/font) -->
<v-btn prepend-icon="mdi-home">ホーム</v-btn>
<!-- 別名で書く(@mdi/js。aliases に登録した名前に $ を付ける) -->
<v-btn prepend-icon="$home">ホーム</v-btn>
@mdi/font では <i class="mdi-home mdi v-icon"> が描画され、::before の content に私用領域の文字(フォントの字形)が入ります。@mdi/js では <i class="v-icon"> の中に <svg class="v-icon__svg" viewBox="0 0 24 24"> が入りました。どちらも幅 24px で、見た目は同じです。
@mdi/font を入れてビルドすると、woff2(403KB)のほかに woff(588KB)・ttf(1,308KB)・eot(1,308KB)も dist にコピーされます。ただし Chromium が実際に読み込んだのは woff2 の1つだけでした(次の節)。
ビルドサイズの実測(ツリーシェイク・アイコン方式)
この節では、同じ社員名簿の画面を3通りの設定でビルドし、ファイルの大きさとブラウザが受け取ったバイト数、ビルド時間がどれだけ違うかが分かります。
「全部登録」から「使った部品だけ+SVG アイコン」に変えると、ブラウザが受け取る量は 2.04MB から 0.76MB に減りました。 vite build の出力(gzip 前後)と、配信して Chromium が受け取った合計です。
| 設定 | JS(gzip) | CSS(gzip) | 受け取った合計 | ビルド |
|---|---|---|---|---|
| 全部登録(components・directives を import)+@mdi/font | 766.66KB(248.05KB) | 864.71KB(126.53KB) | 2,035,015 B | 1.87秒・1,066 モジュール |
| autoImport(vite-plugin-vuetify)+@mdi/font | 419.86KB(141.52KB) | 652.99KB(100.18KB) | 1,476,481 B | 1.50秒・752 モジュール |
| autoImport+@mdi/js(SVG) | 431.42KB(146.19KB) | 329.54KB(46.37KB) | 761,384 B | 0.82秒・753 モジュール |
| 参考:Vuetify なしの素の Vue | 63.15KB(24.93KB) | — | 63,496 B | 0.14秒・10 モジュール |
ビルドした JS の中身を調べると、全部登録では使っていない v-calendar(37か所)・v-date-picker(54か所)・v-stepper(34か所)の文字列が含まれ、autoImport では 0 でした。CSS でも .v-calendar の規則が全部登録では6つ、autoImport では0でした。
autoImport でも CSS が 330KB 残るのは、ユーティリティクラス(d-flex・ma-2 など。手元の概算で約 131KB)と色のクラス(bg-deep-purple など。約 44KB)が vuetify/styles に含まれるためです。SASS 変数の $color-pack: false・$utilities: false で減らせます(次の節)。
読み込み時間は、同じ PC の 127.0.0.1 からの配信で、全部登録 load 416ms・autoImport 431ms・SVG 321ms・素の Vue 50ms でした。回線が遅いほど受け取る量の差が効きます。他の Vue 用 UI ライブラリと同じ画面で比べた結果は、関連記事「Vue UIライブラリ比較|6種で同じ画面を作りサイズを実測」にあります。
- 1vite-plugin-vuetify の autoImport を使うJS 767KB → 420KB。
import * as componentsの行は消す - 2アイコンは @mdi/js にするCSS 653KB → 330KB、フォント 403KB が不要に
- 3動的コンポーネントは手で import する
<component :is>はプラグインが解析できないと公式が明記 - 4使わない色・ユーティリティは SASS で切る
$color-pack: falseで約 44KB、$utilities: falseで約 131KB(概算)
SASS 変数とユーティリティクラスでのカスタマイズ
この節では、角の丸さなど部品の既定値を SASS 変数で一括して変える方法と、ビルド時間への影響が分かります。
部品ごとの細かい既定値(角の丸さ・余白・文字の変形など)は、vuetify/settings の SASS 変数を上書きします。 これには sass(公式の雛形は sass-embedded)が要ります。
// src/styles/settings.scss
@use 'vuetify/settings' with (
$button-border-radius: 20px,
$card-border-radius: 16px
);
// vite.config.js
vuetify({ autoImport: true, styles: { configFile: 'src/styles/settings.scss' } })
sass-embedded を入れずにビルドすると、次のエラーで止まりました。
✗ Build failed in 810ms
error during build:
Build failed with 49 errors:
[plugin vite:css] virtual:plugin-vuetify:styles/main.sass
Error: Preprocessor dependency "sass-embedded" not found. Did you install it? Try `npm install -D sass-embedded`.
npm install -D sass-embedded の後は成功し、出力の CSS に border-radius:20px が入っていました。ただしビルド時間は 1.50秒から 9.23秒に伸びました(Vuetify の全 SASS をコンパイルし直すため)。変数を変える必要が無いうちは configFile を付けないほうが開発が軽くなります。
ユーティリティクラス
余白や並びは、Vuetify に同梱のクラスで書けます。サンプルでは class="d-flex flex-wrap ga-2 mb-6"(横並び・折り返し・隙間 8px・下の余白 24px)を使いました。数字は 4px 単位で、ma-2 は margin 8px、pa-4 は padding 16px です。文字の大きさは v4 で Material Design 3 の名前(text-headline-small・text-body-large など)になり、v3 の text-h5 などは移行の対象です。
Vuetify 2・3・4 の違いと移行
この節では、検索で出てくる以前の書き方(Vuetify 2)がなぜ動かないのか、v3 から v4 で何が変わったのかが分かります。
Vuetify 2 は Vue 2 用で、new Vuetify()・Vue.use(Vuetify) と書きます。Vuetify 3 以降は Vue 3 用で、createVuetify()・app.use() です。 手元で Vuetify 4 に v2 の書き方をすると、次のエラーで止まりました。
// import Vuetify from 'vuetify'; new Vuetify({})
SyntaxError: The requested module '/node_modules/.vite/deps/vuetify.js' does not provide an export named 'default'
// import * as Vuetify from 'vuetify'; new Vuetify.default({})
TypeError: Vuetify.default is not a constructor
| 項目 | Vuetify 2 | Vuetify 3 | Vuetify 4 |
|---|---|---|---|
| Vue | 2.x | 3.0 以上 | 3.5 以上 |
| 初期化 | new Vuetify() |
createVuetify() |
createVuetify() |
| 値の受け渡し | value |
model-value |
model-value |
| デザイン | Material Design 2 | MD2 寄り | Material Design 3(字体・影・幅) |
| 既定テーマ | light | light | system(OS に従う) |
| ボタンの英字 | 大文字 | 大文字 | そのまま |
| サポート | 2025年1月に終了 | 2027年7月27日まで LTS | 開発中 |
v3 → v4 で変わった主な点(公式の移行ガイド)
- 1ブレークポイントmd 960→840、lg 1280→1145、xl 1920→1545、xxl 2560→2138px。
display.thresholdsで v3 の値に戻せる - 2文字クラス
text-h5→text-headline-small、text-body-1→text-body-largeなど MD3 の名前に。codemod で変換できる - 3影(elevation)0〜24 の 25段階から 0〜5 の 6段階に
- 4グリッド(v-row・v-col)負のマージンから CSS gap に。
dense・justify・orderなどの prop はユーティリティクラスへ - 5CSS リセットとレイヤー
* { margin:0; padding:0 }が無くなり、自分の CSS が Vuetify より優先される。レイヤーは5つに - 6v-container上限が md 900→700、lg 1200→1000、xl 1800→1400px。
fill-heightで縦中央にならなくなった - 7v-form のスロット
isValidなどが ref でなくなり.valueを付けない
公式は変換ツール vuetify-codemods と、Vuetify MCP の get_v4_breaking_changes で変更箇所を見つける方法を案内しています。Vue 2 のアプリは、先に Vue 3 へ移行してから Vuetify 2 → 3 → 4 の順に上げます。
他の UI ライブラリとの違い(Element Plus・Quasar・PrimeVue・Tailwind)
この節では、Vue 用の主な UI ライブラリと Vuetify を、見た目の流儀・部品数・周辺機能で比べ、どれを選ぶかの判断表が分かります。
違いは「見た目の流儀を決めてもらうか」と「部品以外に何が付くか」です。 2026年10月29日時点の npm の最新版で整理しました(部品数は各公式の一覧、ライセンスは npm の表記)。
| ライブラリ(版) | 見た目の流儀 | 特徴 | 向く場面 |
|---|---|---|---|
| Vuetify(4.3.1) | Material Design 3 | 部品 105種+labs、レイアウト・テーマ・日本語文言が同梱。MIT | Google 風の見た目でよい業務アプリ・管理画面を速く作る |
| Element Plus(2.14.7) | 独自(Element の流儀) | 表・フォームが豊富。中国語圏で利用が多い。MIT | Material でない、落ち着いた管理画面 |
| Quasar(2.35.2) | Material(独自調整) | 部品に加え CLI で SPA・SSR・PWA・モバイル・デスクトップを1つのコードから。MIT | Web とアプリを同じコードで出したい |
| PrimeVue(5.0.4) | 複数のテーマ+unstyled | 見た目なしモードで Tailwind と組める。ライセンスは npm の LICENSE.md を参照 | 独自デザインを Tailwind で付けたい |
| Tailwind CSS(4.3.3) | 無し(ユーティリティ CSS) | 部品ではなくクラスの集まり。Vue 専用でもない。MIT | デザイナーの指定どおりに1から作る |
Vuetify を選ぶ
見た目を決めてもらい、表・フォーム・ダイアログを揃えて速く作りたい。Material Design に抵抗が無い。
業務アプリ・社内ツール
Quasar を選ぶ
同じコードから Web・PWA・スマホアプリ・デスクトップまで出したい。
マルチプラットフォーム
PrimeVue+Tailwind を選ぶ
部品の動きは借りて、見た目は会社のデザインに合わせたい。
独自デザイン
Tailwind だけで作る
デザインの指定が細かく、部品の見た目を上書きするより1から書くほうが早い。
LP・コーポレートサイト
Tailwind CSS の導入は、関連記事「Tailwind CSS 使い方|v4の導入からつまずき対策まで実行結果つき」で扱っています。
よくあるエラー・つまずきと直し方
この節では、Vuetify を入れた直後に起きやすいエラーと、手元で再現したときの原文、直し方が分かります。
画面が真っ白になるエラーは、ほぼ「v-app が無い」「app.use(vuetify) が無い」の2つです。 アイコンが出ない場合はエラーが出ないため気づきにくく、Vuetify 2 の書き方は import の時点で止まります。
| 症状 | 原文(Chromium のコンソール) | 原因と直し方 |
|---|---|---|
| 真っ白。v-app-bar や v-main を使っている | [Vue warn]: injection "Symbol(vuetify:layout)" not found. と Error: [Vuetify] Could not find injected layout |
一番外側に <v-app> が無い。App.vue の根を v-app で包む |
| 真っ白。v-app はある | injection "Symbol(vuetify:defaults)" not found. と Error: [Vuetify] Could not find defaults instance |
main.js で app.use(vuetify) していない |
| アイコンの場所が空白。エラー無し | (出ない。<i class="mdi-home mdi v-icon"> は描画され、::before が none) |
@mdi/font の CSS(materialdesignicons.css)を import していない。または @mdi/js の別名を登録していない |
| Vuetify 2 の書き方を流用 | SyntaxError: The requested module … does not provide an export named 'default' |
import { createVuetify } from 'vuetify' に書き換える |
| SASS 変数を設定したらビルドが落ちる | Error: Preprocessor dependency "sass-embedded" not found. |
npm install -D sass-embedded |
| 入力欄に「$required」と文字が出る | (出ない) | createRulesPlugin を app.use() していない |
| ルールが効かない | undefined is not a valid value. Rule functions must return boolean true or a string. |
引数つきの組み込みルールは ['$maxLength', 5] と配列で書く |
| 勝手にダークになる | (出ない) | v4 の既定 system。theme.defaultTheme: 'light' を明示 |
| ダイアログが背面に隠れる(開発時のみ) | (公式の移行ガイドに記載) | Vite の依存の事前バンドルで useStack が二重になる。optimizeDeps.include に Vuetify を足し、node_modules/.vite を消す |
1SSR(Nuxt)では ssr: true
公式 FAQ は「Vue 3 は SSR を自動検出しないため、Nuxt などでは createVuetify({ ssr: true }) を手で指定する」と説明している。Nuxt では nuxt.config.ts の vite.plugins に vite-plugin-vuetify を入れ、plugins/ で登録する。
2フォントが Roboto にならない
Vuetify は Roboto を同梱しない。@fontsource/roboto を import するか、雛形どおり unplugin-fonts で読み込む。日本語は別途 Noto Sans JP などを指定する。
3Vue 3.4 以前に入らない
4.x の peerDependencies は vue ^3.5.0。npm が ERESOLVE で止まるときは、先に Vue を 3.5 以上に上げる。
Nuxt での構成そのものは、関連記事「Nuxt 4 入門|作成からビルドまで実行ログと構成図で解説」で扱っています。
よくある質問
Q. Vuetify とは何ですか?
A. Vue 3 の上で動く、Material Design の見た目を持つ UI コンポーネント集です。ボタン・フォーム・表・ダイアログなど 105 種の部品を <v-btn> のようなタグで使い、テーマで色を一括して変えられます。MIT ライセンスで無料です。
Q. Vuetify の読み方は? A. 「ビューティファイ」です。Vue と beautify(美しくする)を合わせた名前です。
Q. Vuetify の使い方を最短で教えてください。
A. npm create vuetify@latest で雛形を作り、npm install → npm run dev です。既存の Vue 3 プロジェクトなら npm i vuetify @mdi/font vite-plugin-vuetify の後、createVuetify() を app.use() に渡し、App.vue の一番外側を <v-app> にします。
Q. Vuetify 3 と 4 のどちらを使えばよいですか?
A. 新規は 4 です。3 は 2027年7月27日まで重大なバグとセキュリティの修正が続きますが、新しい部品は 4 に入ります。既存の 3 のアプリは、公式の移行ガイドと vuetify-codemods で移行します。
Q. Vuetify は Vue 2 で使えますか? A. Vuetify 2.7 が Vue 2 用ですが、2025年1月にサポートが終了しています。Vue 2 自体も終了済みのため、Vue 3 に移行してから Vuetify 3 以降を使います。
Q. v-app は必須ですか?
A. 必須です。v-app-bar・v-navigation-drawer・v-main の位置を計算するのが v-app で、無いと手元では「[Vuetify] Could not find injected layout」で画面が真っ白になりました。
Q. アイコンが表示されません。
A. Vuetify はアイコンを同梱していません。@mdi/font を入れて materialdesignicons.css を import するか、@mdi/js と vuetify/iconsets/mdi-svg を使います。エラーは出ず、アイコンの場所が 24px の空白になります。
Q. ダークモードはどう切り替えますか?
A. useTheme() の change('dark') です。v4 は既定が OS の設定に従う system なので、常にライトにしたいときは defaultTheme: 'light' を書きます。
Q. ビルドが大きいのですが減らせますか? A. vite-plugin-vuetify の autoImport で使った部品だけにし、アイコンを @mdi/js にすると、手元では受け取る量が 2.04MB → 0.76MB になりました。さらに SASS 変数で色のクラスとユーティリティを切れます。
Q. Tailwind CSS と一緒に使えますか? A. 使えますが、公式 FAQ は一般には推奨していません。併用するなら Vuetify 側の色・ユーティリティの生成を止めて、クラス名の衝突を避けます。見た目を Tailwind で付けたいなら、unstyled モードのある PrimeVue のほうが相性がよい選択です。
Q. 日本語の文言(表の件数表示など)にできますか?
A. vuetify/locale の ja を locale.messages に渡し、locale: 'ja' にします。手元では表の下が「1ページあたりの件数:5」「1-5 件目 / 12件」になりました。
Q. Nuxt でも使えますか?
A. 使えます。公式は nuxt.config.ts の vite.plugins に vite-plugin-vuetify を入れ、createVuetify({ ssr: true }) を Nuxt のプラグインで登録する手順を載せています。
まとめ
- Vuetify は Vue 3 用の Material Design の UI コンポーネント集。2026年10月29日時点の最新は 4.3.1、3.x は 2027年7月27日まで LTS、2.x は終了済み。
- 入れ方は
npm i vuetify @mdi/font vite-plugin-vuetify→createVuetify()をapp.use()→ 一番外側を<v-app>。新規はnpm create vuetify@latest。 - 手元の社員名簿では、v-form の検証文言・v-data-table の並べ替え(文字コード順に注意)・v-dialog のフォーカス移動とスクロール停止・ダークテーマの色の入れ替わりを Chromium で確かめた。
- ビルドは「全部登録」2.04MB → 「autoImport」1.48MB → 「autoImport+SVG アイコン」0.76MB。SASS 変数を使うとビルドが 1.5秒 → 9.2秒。
- 真っ白の原因は v-app 無し(Could not find injected layout)か use 忘れ(Could not find defaults instance)。アイコンの空白はエラーが出ない。v4 はブレークポイント・文字クラス・影・既定テーマが v3 と違う。
Vue 側の基礎は、関連記事「Vue 3 Composition APIの使い方|早見表と実行結果」で扱っています。
参考・出典
確認日はいずれも 2026年10月29日です。
- Vuetify「Get started with Vuetify 4 — Installation」:https://vuetifyjs.com/en/getting-started/installation/
- Vuetify「Upgrade guide(v3 → v4)」:https://vuetifyjs.com/en/getting-started/upgrade-guide/
- Vuetify「Browser support」:https://vuetifyjs.com/en/getting-started/browser-support/
- Vuetify「Frequently asked questions」:https://vuetifyjs.com/en/getting-started/frequently-asked-questions/
- Vuetify「Long-term support」:https://vuetifyjs.com/en/introduction/long-term-support/
- Vuetify「Treeshaking」:https://vuetifyjs.com/en/features/treeshaking/
- Vuetify「Theme」:https://vuetifyjs.com/en/features/theme/
- Vuetify「Icon Fonts」:https://vuetifyjs.com/en/features/icon-fonts/
- Vuetify「Display & Platform」:https://vuetifyjs.com/en/features/display-and-platform/
- GitHub「vuetifyjs/create-vuetify」:https://github.com/vuetifyjs/create-vuetify
- npm「vuetify」(版と公開日):https://www.npmjs.com/package/vuetify
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Vuetifyとは・使い方|v4の導入からフォーム・一覧・テーマまで実測」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。