コーヒーゼリーのイラスト

HTML-in-Canvas コンポーネントライブラリ Canvas UI

Canvas UI は HTML-in-Canvas API を活用し、液体シミュレーションやシェーダーといったクリエイティブな UI を構築するためのコンポーネントライブラリです。

Canvas UI は HTML-in-Canvas API を活用し、液体シミュレーションやシェーダーといったクリエイティブな UI を構築するためのコンポーネントライブラリです。HTML-in-Canvas は、<canvas> 要素の子として配置した HTML 要素の描画結果を、2D Canvas や WebGL、WebGPU で利用するための実験的な API です。元の HTML は DOM として保たれるため、Canvas 上の表示と DOM の位置を適切に同期することで、ポインターやキーボードによる操作、アクセシビリティツリーへの参加を維持したまま WebGL エフェクトを適用できます。

Note

HTML-in-Canvas API は、2026 年 7 月時点では Chrome 148〜150 の Origin Trial として提供されている実験的な API です。ローカルで試す場合は Chrome Canary 149 以降で chrome://flags/#canvas-draw-element フラグを有効にします。一般のユーザーに提供する場合は、Origin Trial への登録とトークンの設定が必要です。

各コンポーネントは React, Solid, Vue, Svelte など様々なフレームワークに対応しています。コンポーネントは shadcn/ui レジストリで配布されており、コンポーネントをインストールした後は自分自身のソースコードとして管理します。そのため、コンポーネントのカスタマイズや拡張が容易に行えます。

HTML-in-Canvas API に対応していないブラウザでは、通常の HTML 表示にフォールバックします。DropletsGlass など一部のエフェクトは WebGL オーバーレイとして引き続き動作しますが、HTML の描画結果をテクスチャとして変形する完全な表現には HTML-in-Canvas API が必要です。

この記事では Canvas UI を試してみた様子を紹介します。

Canvas UI のインストール

React で Canvas UI を利用する例を紹介します。shadcn レジストリ形式で配布されているため、コンポーネント単位でインストールを行います。また、あらかじめ shadcn init コマンドを実行しておく必要があります。

npx shadcn@latest init

Canvas UI のコンポーネント一覧から興味があるコンポーネントを探してみましょう。

試しに Droplets コンポーネントをインストールしてみましょう。このコンポーネントは、液体の滴が落ちるようなアニメーションを表現します。shadcn CLI を利用してインストールします。

npx shadcn@latest add @canvas-ui/droplets-react

インストールが完了すると src/components/canvasui/Droplets.tsx が作成されます。これをアプリケーションに組み込むことで、Canvas UI のコンポーネントを利用することができます。

src/components/canvasui/Droplets.tsx
"use client";
 
import {
  useEffect,
  useRef,
  useState,
  useSyncExternalStore,
  type ReactNode,
} from "react";
 
export interface DropletsOptions {
  /** How much rain falls, from a light drizzle to a downpour (0 to 1.25). */
  intensity?: number;
  /** Animation speed multiplier. */
  speed?: number;
  /** Size of the droplet pattern. Higher means smaller drops. */
  scale?: number;
  /** Width of the droplets and their trails. */
  dropWidth?: number;
  /** How elongated the falling droplets are. */
  dropLength?: number;
  /** How strongly droplets refract the content behind them. */
  refraction?: number;
  /** Background blur outside the droplets, like a fogged up window. */
  blur?: number;
  /** Darkens the edges of the canvas (0 to 1). */
  vignette?: number;
  /** How fast the running drops slide down. */
  fallSpeed?: number;
  /** Horizontal wiggle of the running drops. */
  wiggle?: number;
  /** Multiplier for the small static droplets. */
  staticDrops?: number;
  /** Wipe drops off the glass with the pointer. */
  interactive?: boolean;
  /** Radius of the cursor wipe, relative to the screen height. */
  interactionRadius?: number;
  /** How strongly the cursor wipes drops off the glass (0 to 1). */
  interactionStrength?: number;
  /** How much the wipe distorts the content behind it. */
  interactionDistortion?: number;
  /** Tint color layered over the content as [r, g, b] in 0-1 range. */
  tint?: [number, number, number];
  /** Strength of the tint (0 to 1). */
  tintStrength?: number;
}
 
// ...

アプリケーション全体を <Droplets> コンポーネントでラップすると、画面全体に液体の滴が落ちるようなアニメーションが適用されます。

src/App.tsx
import { TodoApp } from "@/components/TodoApp";
import Droplets from "@/components/canvasui/Droplets";
 
function App() {
  return (
    <Droplets className="flex min-h-svh items-center justify-center bg-background p-6">
      <TodoApp />
    </Droplets>
  );
}
 
export default App;

アニメーションが適用されていても、Todo アプリケーションのインタラクティブな操作はそのまま行えることが確認できます。

HTML-in-Canvas API をサポートしていないブラウザでは、WebGL オーバーレイとして滴のアニメーションが表示されます。HTML の描画結果をテクスチャとして変形する表現は行えませんが、インタラクティブな操作はそのまま行えます。

Props を調整することで、液体の滴の落ちる速度や量、滴の大きさなどを変更することができます。例えば blur を調整すると、曇った窓のように背景がぼやける表現を追加することができます。

src/App.tsx
import { TodoApp } from "@/components/TodoApp";
import Droplets from "@/components/canvasui/Droplets";
 
function App() {
  return (
    <Droplets blur={5} className="flex min-h-svh items-center justify-center bg-background p-6">
      <TodoApp />
    </Droplets>
  );
}
 
export default App;

全体的に曇っているような表現が追加され、マウスで画面を擦った場所の部分だけがクリアに見えるような楽しい表現です。

もう少しコンポーネントを見てみましょう。HexFloat コンポーネントは画面を光沢のある六角形タイルに分割し、奥へ傾いたような遠近感と浮遊表現を加えます。カーソルを動かすと、周囲のタイルが平らになり、コンテンツを読み取れる領域が現れます。

npx shadcn@latest add @canvas-ui/hex-float-react

傾いた画面にそのまま文字を入力するのはちょっと不思議な気分です。

Glass コンポーネントはガラスレンズがカーソルを追従するような表現になります。

npx shadcn@latest add @canvas-ui/glass-react

Shatter コンポーネントはカーソルの周囲がガラスの破片のように割れる表現になります。

npx shadcn@latest add @canvas-ui/shatter-react

まとめ

  • Canvas UI は HTML-in-Canvas API を利用して、HTML 要素の描画結果に WebGL エフェクトを適用するコンポーネントライブラリ
  • 元の HTML は DOM として保たれ、適切に実装することでインタラクティブな操作やアクセシビリティを維持できるよう設計されている
  • HTML-in-Canvas API は Chrome の実験的な機能であり、ローカルで試す場合は対応する Chrome Canary で chrome://flags/#canvas-draw-element フラグの有効化が必要
  • HTML-in-Canvas API に対応していないブラウザでは通常の HTML 表示にフォールバックし、一部のエフェクトは WebGL オーバーレイとして動作する
  • React, Solid, Vue, Svelte など様々なフレームワークに対応している
  • コンポーネントは shadcn レジストリ形式で配布されており、npx shadcn@latest add @canvas-ui/<コンポーネント名> でインストールできる
  • 雨粒が流れる Droplets、画面が傾く HexFloat、ガラスレンズがカーソルを追従する Glass、カーソル周辺が割れる Shatter など、Props を調整するだけで多彩な表現を実現できる

参考

記事の理解度チェック

以下の問題に答えて、記事の理解を深めましょう。

記事で紹介されている Canvas UI のコンポーネントの配布方法と、インストール後の扱いとして正しいものはどれですか?

  • npm パッケージとして配布され、node_modules 内の依存パッケージとして管理する

    もう一度考えてみましょう

    記事では shadcn レジストリで配布され、インストール後は自分自身のソースコードとして管理すると説明されています。

  • CDN から読み込む形式で配布され、バージョンは URL のパスで切り替える

    もう一度考えてみましょう

    CDN 経由での配布については記事で触れられていません。

  • リポジトリを clone してビルドする必要があり、コンポーネント単位での導入はできない

    もう一度考えてみましょう

    記事ではコンポーネント単位でインストールを行うと説明されています。

  • shadcn レジストリで配布され、インストール後は自分自身のソースコードとして管理する

    正解!

    記事の通りです。自分のソースコードとして扱えるため、カスタマイズや拡張が容易に行えると説明されています。

Droplets コンポーネントに blur を指定すると、どのような表現が加わると記事で説明されていますか?

  • 滴が落ちる速度が遅くなり、ゆっくり流れ落ちるようになる

    もう一度考えてみましょう

    落下速度に関わるのは記事のコード中にある fallSpeed であり、blur の効果ではありません。

  • 曇った窓のように背景がぼやけ、マウスで擦った場所だけがクリアに見える

    正解!

    記事の通りです。全体が曇ったような表現になり、擦った部分だけが鮮明になると紹介されています。

  • キャンバスの四隅が暗くなり、中央に視線が集まるようになる

    もう一度考えてみましょう

    縁を暗くするのは記事のコード中にある vignette の役割です。

  • 画面全体に色が重なり、指定した色味に染まったように見える

    もう一度考えてみましょう

    コンテンツに色を重ねるのは記事のコード中にある tint と tintStrength です。