mcpField
S
shadcn-inertia

shadcn-inertia

github.com/inertia-rails開発70433 回インストール37 週間前に更新
リポジトリ

shadcn-inertia について

shadcn-inertia は、shadcn/ui コンポーネントを Inertia.js、Rails、React のプロジェクトに適用するスキルです。Next.js や react-hook-form の慣例を Inertia のパターンに置き換える方法を、フォーム、ナビゲーション、フラッシュ通知、テーマ設定まで解説します。

主な機能

  1. 01Next.js のパターンを Inertia 用に変換
  2. 02Inertia フォームフィールドの指針
  3. 03SPA ナビゲーションと URL ダイアログ
  4. 04フラッシュ通知とトーストの連携
  5. 05next-themes を使わないダークモード設定

活用シーン

  1. 01shadcn フォームを Inertia 向けに適応
  2. 02サーバー側テーブルに並べ替えを追加
  3. 03フラッシュ通知を Sonner トーストに接続
  4. 04ダークモード切り替え時のちらつきを防止

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/inertia-rails/skills --skill shadcn-inertia

インストール後、Claude Code で/shadcn-inertiaを入力して読み込まれたか確認します。

同梱ファイルreferences/components.mdreferences/flash-toast.md

詳細

Inertia Rails 向け shadcn/ui

Inertia.js + Rails + React 向けに適応した shadcn/ui のパターンです。Next.js 向けではありません。

shadcn の例を使う前に、次の点を確認してください。

  • react-hook-form + zod を使用していますか? → Inertia の <Form> + name 属性に置き換えてください。Inertia は CSRF、エラー、リダイレクト、処理中の状態を管理します。react-hook-form を使うと、これらと競合します。
  • 'use client' を使用していますか? → 削除してください。Inertia には RSC がないため、すべてのコンポーネントがクライアントコンポーネントです。
  • next/link、next/head、useRouter() を使用していますか? → Inertia の <Link>、<Head>、router に置き換えてください。

Next.js のデフォルト設定との主な違い

shadcn のデフォルト(Next.js)Inertia での対応
'use client' ディレクティブ削除します(RSC がないため不要です)
react-hook-form + zodInertia の <Form> コンポーネント
FormField、FormItem、FormMessage通常の <Input name="..."> + errors.field
next-themesCSS クラス方式 + @custom-variant
useRouter()(Next)@inertiajs/react の router
next/link@inertiajs/react の <Link>
next/head@inertiajs/react の <Head>

shadcn の FormField、FormItem、FormLabel、FormMessage コンポーネントは絶対に使用しないでください — 内部で react-hook-form の useFormContext に依存しているため、それなしではクラッシュします。 Inertia の <Form> 内では、name 属性を指定した通常の shadcn Input/Label/Select を使い、 レンダー関数の errors オブジェクトからエラーを表示してください(以下の例を参照)。

セットアップ

npx shadcn@latest init を実行します。存在しない場合は、tsconfig.json に @/ の解決エイリアスを追加してください。 vite.config.ts に @/ の解決エイリアスを追加しないでください — vite-plugin-ruby がすでに提供しています。

Inertia の <Form> 内での shadcn 入力コンポーネント

Inertia の <Form> 内では、name 属性を指定した通常の shadcn Input/Label/Button を使用してください。 <Form> API の全容については inertia-rails-forms スキルを参照してください。このセクションでは、shadcn に固有の適応方法のみを説明します。

重要なパターン: shadcn の FormField/FormItem/FormMessage を、通常の コンポーネント + 手動でのエラー表示に置き換えます。

// shadcn error display pattern (replaces FormMessage):
<Label htmlFor="name">Name</Label>
<Input id="name" name="name" />
{errors.name && <p className="text-sm text-destructive">{errors.name}</p>}

Inertia の <Form> と連携させるには、<Select> に name prop が必要です。shadcn の例では、 react-hook-form が異なる方法で値を管理するため、省略されています。

<Select name="role" defaultValue="member">
  <SelectTrigger><SelectValue placeholder="Select role" /></SelectTrigger>
  <SelectContent>
    <SelectItem value="admin">Admin</SelectItem>
    <SelectItem value="member">Member</SelectItem>
  </SelectContent>
</Select>

Inertia ナビゲーションを使ったダイアログ

import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { router } from '@inertiajs/react'

function UserDialog({ open, user }: { open: boolean; user: User }) {
  return (
    <Dialog
      open={open}
      onOpenChange={(isOpen) => {
        if (!isOpen) {
          router.replaceProp('show_dialog', false)
        }
      }}
    >
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{user.name}</DialogTitle>
        </DialogHeader>
        {/* content */}
      </DialogContent>
    </Dialog>
  )
}

サーバーサイドソートを使ったテーブル

shadcn の <Table> は通常どおりレンダーされます。Inertia 固有の部分は、router.get によるソートです。

const handleSort = (column: string) => {
  router.get('/users', { sort: column }, { preserveState: true })
}

<TableHead onClick={() => handleSort('name')} className="cursor-pointer">
  Name {sort === 'name' && '↑'}
</TableHead>

SPA ナビゲーションを維持するため、行リンクには <a> ではなく <Link> を使用してください。

フラッシュメッセージを使ったトースト

フラッシュの設定(flash_keys)は inertia-rails-controllers にあります。フラッシュへのアクセス(usePage().flash)は inertia-rails-pages にあります。このセクションでは、トースト UI の接続のみを扱います。

必須 — Sonner を使ったフラッシュベースのトーストを実装する場合は、ファイル全体を読んでください。 references/flash-toast.md(約80行)— useFlash フックと Sonner トーストプロバイダーの全容です。トースト UI を使わずにフラッシュ値を読み取るだけの場合は、読み込まないでください。

重要な注意点:Rails イニシャライザーの flash_keys は、TypeScript の FlashData 型と一致させる必要があります。両方も更新しない限り、success/error は使用しないでください。

ダークモード(next-themes なし)

npx shadcn@latest init は、ライト/ダーク用の CSS 変数と、CSS(Tailwind v4)内の @custom-variant dark (&:is(.dark *)); を生成します。CSS 変数自体に追加の設定は不要です。

重要 — テーマの誤表示によるちらつき(FOUC)を防止する: Next.js では自動的に処理されますが、Inertia では処理されません。<head> 内(React の ハイドレーション前)にインラインスクリプトを追加し、Inertia のエントリーポイントで initializeTheme() を呼び出してください。

<%# app/views/layouts/application.html.erb — in <head>, before any stylesheets %>
<script>
  document.documentElement.classList.toggle(
    "dark",
    localStorage.appearance === "dark" ||
      (!("appearance" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches),
  );
</script>
// app/frontend/entrypoints/inertia.tsx
import { initializeTheme } from '@/hooks/use-appearance'
initializeTheme() // must run before createInertiaApp

next-themes の代わりに、useAppearance フック(ライト/ダーク/システムのモード、localStorage への永続化、 matchMedia リスナー)を使用してください。<html> の .dark クラスで切り替えます — プロバイダーは不要です。

トラブルシューティング

症状原因対処方法
FormField/FormMessage がクラッシュするreact-hook-form に依存する shadcn のフォームコンポーネントを使用している通常の Input/Label と errors.field の表示に置き換える
Select の値が送信されないname プロパティがない<Select> に name="field" を追加する — shadcn の例では省略されています
ダイアログが予期せず閉じるonOpenChange ハンドラーがない、または正しくないonOpenChange={(open) => { if (!open) closeHandler() }} を使用する
間違ったテーマが一瞬表示される(FOUC)<head> にインラインの <script> がないスタイルシートより前にダークモード用スクリプトを追加する(「ダークモード」セクションを参照)

関連スキル

  • フォームコンポーネント → inertia-rails-forms(<Form> のレンダー関数、useForm)
  • フラッシュ設定 → inertia-rails-controllers(flash_keys イニシャライザー)
  • フラッシュへのアクセス → inertia-rails-pages(usePage().flash)
  • URL 駆動型ダイアログ → inertia-rails-pages(router.get パターン)

参考資料

上記に示したもの以外の shadcn コンポーネント(Accordion、Sheet、Tabs、DropdownMenu、 Inertia のパターンを使った AlertDialog)を構築する場合は、references/components.md(約 300 行)を読み込んでください。

基本的な Form、Select、Dialog、Table の使用では、components.md を読み込まないでください — 上記の例で十分です。

コメント