0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【PrimeVue】かんたん!ダークモードの対応

Last updated at Posted at 2025-12-16

つづき。

おい!ダークモードどうやるんだよ!の声が聞こえてくるので、そちらも解説します。

なんと PrimeVue はダークモードにも標準対応しています。
デフォルトでは、OSのテーマに依存するようになってます。

でも実際の挙動を考えると、テーマを切り替えるためのトグルスイッチを設けたいですよね。

Laravel 標準の実装

Laravel は認証込みのスターターキットを入れるといろいろ入っています。

  • useAppearance.ts
    • フロント側でモード設定を Cookie や LocalStorage に書き込む
  • HandleAppearance.php
    • Middleware で Cookie を読み込んで、blade 側に渡す
  • app.blade.php
    • 現在のモード設定を受け取り <html> タグに反映させる
    • <html class="dark">

テンプレートなのでこれを採用してもよいのですが、こんなちゃんとしなくてもよいです!

LocalStorage を用いた実装

TailwindPrimeVue 双方、任意のクラスに反応してくれる仕組みがあります。
今回は .dark に反応してくれるようにそれぞれを設定します。

まずは app.css@custom-variant dark の設定を行います。

resources/css/app.css
  @import 'tailwindcss';
  @import "tailwindcss-primeui";

+ @custom-variant dark (&:where(.dark, .dark *));

次に app.ts の設定に darkModeSelector を登録します。

resources/js/app.ts
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .use(PrimeVue, {
        theme: {
          preset: Aura,
+         options: {
+           darkModeSelector: '.dark',
+         },
        },
        locale: Ja,
      })
      .mount(el)
  },

そして app.blade.php にある $appearance の残骸を削除します。
(これがテンプレートにあるの消し忘れなんじゃないかなぁ...?)

resources/views/app.blade.php
<!DOCTYPE html>
- <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"  @class(['dark' => ($appearance ?? 'system') == 'dark'])>
+ <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
      <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">

そしたら DarkMode を制御する Composable を作成していきます。
LocalStorage を利用していて、 darkwatch() はシングルトンとして動作させます。

初回に localStorage.setItem('dark', String(value)) が動いちゃうのが嫌だけど、、、
シンプルさ重視で!

まぁ LocalStorage なので、値のサニタイズをやってると思えば無駄ではないか。

もし初期状態を OS のテーマにしたい場合は、以下の設定を読み出すと良いです。
window.matchMedia("(prefers-color-scheme: dark)").matches

resources/js/composable/useDarkMode.ts
import { ref, watch } from 'vue'

// 初期状態を LocalStorage から読み出す
const dark = ref<boolean>(localStorage.getItem('dark') === 'true')

// 状態が変わったら LocalStorage と HTML 属性を同期する
watch(dark, (value) => {
  localStorage.setItem('dark', String(value))

  document.documentElement.classList.toggle('dark', value)
}, { immediate: true })

export const useDarkMode = () => {
  return { dark }
}

これを app.tssetup() で呼び出してあげると、常にダークモードが実行されます。

実はここって Vue 最上位の setup エリアなので、コンポーネントで書けることは何でも書けるんですよね。
各レイアウトの共通処理は、ここに書くと良いです。

resources/js/app.ts
+ import { useDarkMode } from '@/composable/useDarkMode'


  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      //...
      .mount(el)

+   useDarkMode()
  },

ダークモードを操作する処理はこのように書きます。

<template>
  <div class="m-4">
    <ToggleSwitch v-model="dark" />
  </div>
</template>

<script setup lang="ts">
import ToggleSwitch from 'primevue/toggleswitch'

import { useDarkMode } from '@/composable/useDarkMode'

const { dark } = useDarkMode()
</script>

スイッチを押すとダークモードが切り替わります!!
ちゃんと再読み込みしても、モードが維持されてます!

Animation.gif

追伸:Tailwind のダークモード

Tailwind でダークモードを扱うには dark: というプレフィックスを付ける必要があります。
なので light で背景色を薄くした場合には、dark で濃くするクラスを忘れずに付与しましょう

<template>
  <div class="
    bg-primary-100 p-4
    dark:bg-primary-900
  ">
    <div>両テーマ対応!</div>
    <ToggleSwitch v-model="dark" />
  </div>
</template>

Animation.gif

もし light と dark の組み合わせを記録したい場合は、Theme をいじくりましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?