🐣

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