Michael Charles Aubrey

https://MichaelCharl.es/Aubrey

OverlayScrollbarsを使ったTauriアプリのスクロールバーのスタイリング

OverlayScrollbarsを使ったTauriアプリのスクロールバーのスタイリング

Michael Charles Aubrey // Mon Aug 04 2025

サイドプロジェクトで作っている Tauri アプリで、カスタムスクロールバーがなかなか思うように動かず、苦労していました。以前は::-webkit-scrollbarを指定するだけで済んでいたのですが、最近はどうもうまくいきません。GitHub のx4080さんがoverlayscrollbarsというライブラリを教えてくれて、こちらは問題なく動きました。ただ、設定の手順が思っていたほど分かりやすくなかったので、動かすまでの流れを簡単にまとめておきます。

ここで扱うのは、React で書いて Tailwind CSS でスタイルを当てている Tauri アプリです。別の構成でも、少し手を加えれば応用できるはずです。

まず、overlayscrollbarsをインストールしました

npm install overlayscrollbars

続いて、importoverlayscrollbarsのスタイルを CSS に読み込み、あわせてカスタムスクロールバー用のスタイルも書きました。

@import "overlayscrollbars/overlayscrollbars.css";

.os-theme-custom.os-scrollbar {
  --os-size: 8px;
  --os-padding-perpendicular: 0px;
  --os-padding-axis: 0px;
}

.os-theme-custom.os-scrollbar .os-scrollbar-track {
  background: rgba(120, 90, 200, 0.12);
  border-radius: 4px;
}

.os-theme-custom.os-scrollbar .os-scrollbar-handle {
  background: rgba(80, 60, 180, 0.45);
  border-radius: 4px;
  transition: background-color 0.2s ease;
}

.os-theme-custom.os-scrollbar .os-scrollbar-handle:hover {
  background: rgba(80, 60, 180, 0.7);
}

スクロールする要素でoverlayscrollbarsを初期化するために、こんなフックを用意しました。この書き方ができるのは Tailwind を使っているおかげで、.overflow-y-autooverflow-autoをそのままセレクタとして拾えます。Tailwind を使っていない場合は、別の手を考える必要があります。

import { OverlayScrollbars } from "overlayscrollbars";
import { useEffect } from "react";

export const useOverlayScrollbars = () => {
  useEffect(() => {
    // すべてのスクロール可能な要素でOverlayScrollbarsを初期化
    const initScrollbars = () => {
      // メインのスクロール可能なエリアをターゲットにする
      const scrollableElements = [
        document.body,
        document.querySelector('[data-scrollable="true"]'),
        ...document.querySelectorAll(".overflow-y-auto"),
        ...document.querySelectorAll(".overflow-auto"),
      ].filter(Boolean) as Element[];

      scrollableElements.forEach((element) => {
        const htmlElement = element as HTMLElement;
        if (
          htmlElement &&
          !htmlElement.hasAttribute("data-overlayscrollbars-initialize")
        ) {
          OverlayScrollbars(htmlElement, {
            scrollbars: {
              theme: "os-theme-custom",
              autoHide: "never",
            },
          });
          htmlElement.setAttribute("data-overlayscrollbars-initialize", "true");
        }
      });
    };

    // 即座に初期化
    initScrollbars();

    // DOM変更時に再初期化(動的コンテンツ用)
    const observer = new MutationObserver(() => {
      setTimeout(initScrollbars, 100);
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ["class"],
    });

    return () => {
      observer.disconnect();
      // すべてのOverlayScrollbarsインスタンスをクリーンアップ
      document
        .querySelectorAll("[data-overlayscrollbars-initialize]")
        .forEach((element) => {
          const instance = OverlayScrollbars(element as HTMLElement);
          if (instance) {
            instance.destroy();
          }
        });
    };
  }, []);
};

あとはApp.tsxでこのフックを呼ぶだけです。

import { useOverlayScrollbars } from "./hooks/useOverlayScrollbars";

function App() {
  // 初期状態...

  // カスタムスクロールバーを初期化
  useOverlayScrollbars();

  // その他のフック...

  return <main>{/* アプリのコンテンツ ... */}</main>;
}

export default App;

これで終わりです。今のところ、サイドプロジェクトの Snappad ではこの方法でスクロールバーがきちんとスタイリングできています。

Snappad

Michael Charles Aubrey

Developer at Maki
Based in Akita, Japan

Connect

© 2026 Michael Charles Aubrey. All rights reserved.

Born in Florida 🏝️ • Lives in Akita 👹