🐣
Vue3 + Quasarで個人的に使うコンポーネントまとめ
はじめに
この記事は、Quasar Framework を使った開発で 「ここらへん覚えておけば大体なんとかなるか」 と感じたコンポーネントとパターンをまとめたものです。
絶対に覚えておくべきものではないと思いますが、かくいう私が忘れん坊なので、ほぼ自分用のチートシートです。
動作確認環境
- Quasar v2.18.6(記事執筆時点(2026年1月)の最新)
- Vue 3 + Composition API(defineComponent + setup形式)
1. ボタン(q-btn)
基本のボタン
<q-btn label="ボタン" color="primary" @click="onClick" />
スタイルの使い分け
| スタイル | 用途 | コード |
|---|---|---|
| デフォルト | メインアクション | <q-btn label="保存" color="primary" /> |
| unelevated | 影なしのメインボタン | <q-btn unelevated label="登録" color="primary" /> |
| outline | サブアクション | <q-btn outline label="キャンセル" color="grey" /> |
| flat | テキストリンク風 | <q-btn flat label="詳細を見る" color="primary" /> |
ローディング状態
<q-btn
label="送信"
color="primary"
:loading="isLoading"
@click="onSubmit"
/>
サイズ指定
<!-- 小さいボタン -->
<q-btn dense label="小" />
<!-- 大きいボタン -->
<q-btn size="xl" label="大" />
アイコン付きボタン
<q-btn icon="add" label="新規作成" color="primary" />
<q-btn icon="delete" color="negative" />
2. フォーム系
2-1. テキスト入力(q-input)
基本
<q-input v-model="name" label="名前" />
outlinedスタイル(よく使う)
<q-input v-model="email" label="メールアドレス" outlined />
バリデーション付き
<q-input
v-model="email"
label="メールアドレス"
outlined
:rules="[
val => !!val || '必須項目です',
val => /.+@.+\..+/.test(val) || '正しい形式で入力してください'
]"
/>
マスク入力(電話番号など)
<q-input
v-model="phone"
label="電話番号"
outlined
mask="###-####-####"
placeholder="090-1234-5678"
/>
パスワード(表示切替付き)
PasswordInput.vue
<template>
<q-input
v-model="password"
label="パスワード"
outlined
:type="showPassword ? 'text' : 'password'"
>
<template #append>
<q-icon
:name="showPassword ? 'visibility' : 'visibility_off'"
class="cursor-pointer"
@click="showPassword = !showPassword"
/>
</template>
</q-input>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const password = ref('')
const showPassword = ref(false)
return {
password,
showPassword,
}
}
})
</script>
2-2. セレクトボックス(q-select)
基本
<q-select
v-model="selected"
:options="['選択肢A', '選択肢B', '選択肢C']"
label="項目を選択"
outlined
/>
オブジェクト配列を使う場合(個人的にめっちゃ使う)
UserSelect.vue
<template>
<q-select
v-model="selectedUser"
:options="userList"
option-label="name"
option-value="id"
label="ユーザーを選択"
outlined
emit-value
map-options
/>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const selectedUser = ref(null)
const userList = [
{ id: 1, name: '田中太郎' },
{ id: 2, name: '佐藤花子' },
{ id: 3, name: '鈴木一郎' },
]
return {
selectedUser,
userList,
}
}
})
</script>
クリアボタン付き
<q-select
v-model="selected"
:options="options"
label="選択(クリア可)"
outlined
clearable
/>
複数選択
<q-select
v-model="selectedItems"
:options="options"
label="複数選択"
outlined
multiple
use-chips
/>
2-3. チェックボックス / ラジオ
チェックボックス
<q-checkbox v-model="agreed" label="利用規約に同意する" />
ラジオボタン
<div class="q-gutter-sm">
<q-radio v-model="gender" val="male" label="男性" />
<q-radio v-model="gender" val="female" label="女性" />
<q-radio v-model="gender" val="other" label="その他" />
</div>
2-4. フォーム送信(q-form)
BasicForm.vue
<template>
<q-form @submit.prevent="onSubmit" class="q-gutter-md">
<q-input
v-model="form.name"
label="名前"
outlined
:rules="[val => !!val || '必須項目です']"
/>
<q-input
v-model="form.email"
label="メール"
outlined
:rules="[val => !!val || '必須項目です']"
/>
<q-btn type="submit" label="送信" color="primary" />
</q-form>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const form = ref({
name: '',
email: '',
})
const onSubmit = () => {
console.log('送信:', form.value)
}
return {
form,
onSubmit,
}
}
})
</script>
3. 通知系
3-1. ローディング($q.loading)
プラグインを使用すると更にリッチなものも実装できます。
プラグインに関してはconfigファイルでの設定が必要となりますので、一部抜粋して紹介します。
- コンポーネント(<q-btn> 等)は設定不要で使える
- プラグイン($q.xxx)は設定が必要
quasar.config.js(プロジェクトのルートにあるファイル)
module.exports = configure(function (ctx) {
return {
// ... 他の設定 ...
framework: {
plugins: ['Loading', 'Notify', 'Dialog'], // ← ここに追加
},
// ... 他の設定 ...
}
})
<script>
import { defineComponent } from 'vue'
import { useQuasar } from 'quasar' // ← これが必要
export default defineComponent({
setup() {
const $q = useQuasar() // ← これで $q が使える
const fetchData = async () => {
$q.loading.show()
try {
await api.getData()
} finally {
$q.loading.hide()
}
}
return {
fetchData,
}
}
})
</script>
メッセージ付き
$q.loading.show({
message: 'データを読み込み中...'
})
3-2. 通知($q.notify)
成功通知
$q.notify({
type: 'positive',
message: '保存しました',
position: 'top',
})
エラー通知
$q.notify({
type: 'negative',
message: 'エラーが発生しました',
position: 'top',
})
警告通知
$q.notify({
type: 'warning',
message: '入力内容を確認してください',
position: 'top',
})
カスタム通知
$q.notify({
color: 'primary',
icon: 'info',
message: 'お知らせがあります',
position: 'top-right',
timeout: 3000,
})
3-3. 確認ダイアログ($q.dialog)
基本の確認ダイアログ
$q.dialog({
title: '削除確認',
message: 'このデータを削除しますか?',
cancel: true,
persistent: true,
}).onOk(() => {
console.log('削除実行')
}).onCancel(() => {
console.log('キャンセル')
})
ボタンをカスタマイズ
$q.dialog({
title: '変更確認',
message: '保存してよろしいですか?',
ok: {
label: 'はい',
color: 'primary',
},
cancel: {
label: 'いいえ',
color: 'grey',
flat: true,
},
}).onOk(() => {
// 保存処理
})
入力付きダイアログ
$q.dialog({
title: 'メモを入力',
message: '内容を入力してください',
prompt: {
model: '',
type: 'text',
},
cancel: true,
}).onOk((data) => {
console.log('入力値:', data)
})
3-4. 例
NotificationExample.vue
<template>
<div class="q-gutter-md">
<q-btn label="データ取得" color="primary" @click="fetchData" />
<q-btn label="保存" color="positive" @click="saveData" />
<q-btn label="削除" color="negative" @click="confirmDelete" />
</div>
</template>
<script>
import { defineComponent } from 'vue'
import { useQuasar } from 'quasar'
export default defineComponent({
setup() {
const $q = useQuasar()
// ローディング + 成功通知
const fetchData = async () => {
$q.loading.show()
try {
// API呼び出し
await new Promise(resolve => setTimeout(resolve, 1000))
$q.notify({
type: 'positive',
message: 'データを取得しました',
position: 'top',
})
} catch (error) {
$q.notify({
type: 'negative',
message: 'エラーが発生しました',
position: 'top',
})
} finally {
$q.loading.hide()
}
}
// 確認ダイアログ + 保存
const saveData = () => {
$q.dialog({
title: '保存確認',
message: '保存してよろしいですか?',
ok: { label: 'はい', color: 'primary' },
cancel: { label: 'いいえ', flat: true },
}).onOk(async () => {
$q.loading.show()
// 保存処理
await new Promise(resolve => setTimeout(resolve, 500))
$q.loading.hide()
$q.notify({
type: 'positive',
message: '保存しました',
position: 'top',
})
})
}
// 削除確認
const confirmDelete = () => {
$q.dialog({
title: '削除確認',
message: 'このデータを削除しますか?この操作は取り消せません。',
cancel: true,
persistent: true,
}).onOk(() => {
console.log('削除実行')
})
}
return {
fetchData,
saveData,
confirmDelete,
}
}
})
</script>
4. レイアウト
ページ構造(q-page)
<template>
<q-page class="q-pa-md">
<h1 class="text-h5 q-mb-md">ページタイトル</h1>
<div>コンテンツ</div>
</q-page>
</template>
5. アイコン(q-icon)
基本
<q-icon name="home" />
<q-icon name="settings" />
<q-icon name="person" />
サイズ・色の変更
<q-icon name="star" size="xs" />
<q-icon name="star" size="sm" />
<q-icon name="star" size="md" />
<q-icon name="star" size="lg" />
<q-icon name="star" size="xl" />
<q-icon name="favorite" color="red" />
<q-icon name="check_circle" color="positive" />
Material Icons の一覧は Google Fonts Icons
6. Composition API での使い方(defineComponent + setup形式)
useQuasar() の基本
index.vue
<script>
import { defineComponent, ref } from 'vue'
import { useQuasar } from 'quasar'
export default defineComponent({
setup() {
const $q = useQuasar()
// ローディング
const showLoading = () => {
$q.loading.show()
}
const hideLoading = () => {
$q.loading.hide()
}
// 通知
const showNotify = () => {
$q.notify({ message: 'Hello' })
}
// ダイアログ
const showDialog = () => {
$q.dialog({ title: '確認', message: '本当に?' })
}
// 画面サイズの取得
const checkScreenSize = () => {
console.log('幅:', $q.screen.width)
console.log('mdより小さいか:', $q.screen.lt.md)
}
return {
showLoading,
hideLoading,
showNotify,
showDialog,
checkScreenSize,
}
}
})
</script>
7. よく使う CSS ヘルパークラス
スペーシング
| クラス | 意味 |
|---|---|
q-ma-{size} |
margin 全方向 |
q-pa-{size} |
padding 全方向 |
q-mt-{size} |
margin-top |
q-mb-{size} |
margin-bottom |
q-ml-{size} |
margin-left |
q-mr-{size} |
margin-right |
q-mx-{size} |
margin 左右 |
q-my-{size} |
margin 上下 |
q-pt-{size} |
padding-top |
q-pb-{size} |
padding-bottom |
q-gutter-{size} |
子要素の間隔 |
size: none, xs, sm, md, lg, xl
<div class="q-pa-md q-mb-lg">
<div class="q-gutter-md">
<q-btn label="ボタン1" />
<q-btn label="ボタン2" />
</div>
</div>
Flexbox
| クラス | 意味 |
|---|---|
flex |
display: flex |
row |
横並び |
column |
縦並び |
justify-center |
中央寄せ(横) |
justify-between |
両端寄せ |
justify-end |
右寄せ |
items-center |
中央寄せ(縦) |
items-start |
上寄せ |
items-end |
下寄せ |
wrap |
折り返しあり |
no-wrap |
折り返しなし |
content-start |
複数行の上寄せ |
<!-- 中央寄せ -->
<div class="flex justify-center items-center" style="height: 200px;">
中央に配置
</div>
<!-- 両端寄せ -->
<div class="flex justify-between items-center">
<span>左側</span>
<span>右側</span>
</div>
<!-- 縦並び中央寄せ -->
<div class="column items-center q-gutter-md">
<q-btn label="ボタン1" />
<q-btn label="ボタン2" />
</div>
<!-- 横並び + 折り返し -->
<div class="row wrap q-gutter-sm">
<q-btn label="1" />
<q-btn label="2" />
<q-btn label="3" />
</div>
テキスト
| クラス | 意味 |
|---|---|
text-bold |
太字 |
text-weight-medium |
中太字 |
text-center |
中央揃え |
text-right |
右揃え |
text-left |
左揃え |
text-h5, text-h6
|
見出しサイズ |
text-body1, text-body2
|
本文サイズ |
text-caption |
小さいテキスト |
ellipsis |
省略表示(...) |
text-grey-7 |
グレー |
text-grey-10 |
濃いグレー |
text-primary |
テーマカラー |
text-negative |
エラー色 |
text-positive |
成功色 |
<p class="text-h6 text-bold q-mb-md">タイトル</p>
<p class="text-body1">本文テキスト</p>
<p class="text-caption text-grey-7">補足テキスト</p>
<!-- 省略表示 -->
<p class="ellipsis" style="max-width: 200px;">
長いテキストは省略されます...
</p>
サイズ・幅
| クラス | 意味 |
|---|---|
full-width |
width: 100% |
full-height |
height: 100% |
fit |
width & height 100% |
その他よく使う
| クラス | 意味 |
|---|---|
cursor-pointer |
カーソルをポインターに |
rounded-borders |
角丸 |
shadow-1 ~ shadow-24
|
影 |
bg-grey-2 |
背景グレー(薄い) |
bg-grey-3 |
背景グレー |
bg-primary |
背景テーマカラー |
bg-white |
背景白 |
<!-- カード風 -->
<div class="q-pa-md bg-grey-2 rounded-borders shadow-2">
カードっぽいやつ
</div>
<!-- クリック可能な要素 -->
<div class="cursor-pointer" @click="onClick">
クリックできます
</div>
レスポンシブ表示切替
| クラス | 意味 |
|---|---|
gt-xs |
xs より大きい時に表示 |
gt-sm |
sm より大きい時に表示 |
gt-md |
md より大きい時に表示 |
lt-sm |
sm より小さい時に表示 |
lt-md |
md より小さい時に表示 |
lt-lg |
lg より小さい時に表示 |
<!-- PCのみ表示 -->
<div class="gt-sm">
PC用コンテンツ
</div>
<!-- モバイルのみ表示 -->
<div class="lt-md">
モバイル用コンテンツ
</div>
まとめ
チートシートというには膨大な量ですが、これだけあればいろんなレイアウトやパターンが素早く実装できます。
またQuasar コンポーネントの内部スタイルを変更したい場合、:deep() でカスタマイズも可能なので、業務システムなどのレイアウトでは1からコンポーネントを作成するよりもずっと楽ですね。
公式ドキュメントも充実しているので、より詳しく知りたい方は見てください!
Discussion