🎮

Railsプロジェクトにshadcn/uiを導入する方法 + v0でUIを作る手順サンプル

に公開

「ActiveRecord だけは手放せない。でも、フロントは React + Tailwind で高速に組み、しかも生成 AI で UI を自動生成できたら最高じゃないか?」──そんな欲張りなフルスタック Rails エンジニアのために、本記事では shadcn/ui と v0 を “Rails × Vite” 環境へ滑らかにインストールし、AI に自然言語で画面を作らせるまでの最短ルートを解説します。

“Stimulus も好きだけど、複雑な UI はやっぱり React のほうがラク。
とはいえ、gem でごちゃごちゃするのは嫌だ…”

そのモヤモヤ、ここでスッキリさせましょう。

手順は「Rails に Vite を載せている」前提からスタート。Tailwind のセットアップでつまずかないコツから、npx shadcn@latest init 一発でボタンを出現させる快感、そして v0 に「簡単なログイン画面を作って」とつぶやくだけで完成する AI ドリブン UI まで、実践コードを交えつつ一気に駆け抜けます。

読み終える頃には “Vibe Coding!!” とつぶやきながら、新規プロジェクトを shadcn/ui で彩り、AI を組み込んだ UX を Rails 上に展開する方法が手に入るはずです。

Railsにshadcn/uiを導入するモチベーション

  • v0と連携して自然言語でUIを作りたい
  • ActiveRecordは素晴らしいのでRails使いたい
  • Stimulusよりvite+Reactのほうが使いやすい

実際の手順

前回の記事で作成したRuby on Rails + Vite + React + TypeScript の開発環境から進めていくことにします。

https://zenn.dev/yukito0616/articles/6fd49df4c6cd58

manual installとかgemのshadcn-uiとか色々試していてハマったのですが、結論、vite のインストール手順をなぞるのが早いです。

https://ui.shadcn.com/docs/installation/vite

vite_railsの敷いてくれたレールにうまく乗っけるようにいい感じに手順をカスタマイズする必要があります。

Railsプロジェクト自体は作成できているので、Step2の "Add Tailwind CSS"から実行する。

Tailwind CSSの追加

npm install tailwindcss @tailwindcss/vite

3.Edit tsconfig.json file、および4.Edit tsconfig.app.json fileは vite-railsがいい感じに設定してくれているので飛ばしてOK。

vite.config.tsでtailwindcssのpluginをロードするようにする

npm install -D @types/node

vite.config.ts

import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import path from "path";
import { defineConfig } from "vite";
import RubyPlugin from "vite-plugin-ruby";

export default defineConfig({
  build: {
    manifest: true,
    rollupOptions: {
      input: "./app/javascript/entrypoints/application.tsx",
    },
  },
  plugins: [RubyPlugin(), react(), tailwindcss()],
  server: {
    hmr: true,
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./app/javascript"),
    },
  },
});

vite-railsが作成してくれたvite.config.tsのplugins に tailwindcss()だけ指定すればOK。

shadcn の初期設定コマンドを実行

ここまで来れば、shadcnの初期設定コマンドが実行できるようになるはずです。

npx shadcn@latest init

Buttonコンポーネントを追加してみる

npx shadcn@latest add button

HelloWorld.tsx

import { Button } from "./ui/button";

export default function HelloWorld() {
  return <Button>Click me</Button>;
}

初期設定でNeutralを選択していた場合は、このようなボタンが表示されていればOK

v0で作成されたログインフォームを追加してみる

v0にある程度まとまったコンポーネントを作らせてみましょう。

途中プレビューが表示されなかったので再度指示を出していますが、指示は「簡単なログイン画面のモックを作成してください」のたったの一行です。

LoginForm.tsx

import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

export default function LoginForm() {
  return (
    <div className="flex min-h-screen items-center justify-center p-4">
      <Card className="w-full max-w-md">
        <CardHeader>
          <CardTitle className="text-2xl">ログイン</CardTitle>
          <CardDescription>アカウントにログインしてください</CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="space-y-2">
            <Label htmlFor="email">メールアドレス</Label>
            <Input id="email" type="email" placeholder="example@example.com" />
          </div>
          <div className="space-y-2">
            <Label htmlFor="password">パスワード</Label>
            <Input id="password" type="password" />
          </div>
          <div className="flex items-center justify-between">
            <div className="flex items-center space-x-2">
              <Checkbox id="remember" />
              <Label htmlFor="remember" className="text-sm">
                ログイン情報を記憶する
              </Label>
            </div>
            <a href="#" className="text-sm text-primary hover:underline">
              パスワードをお忘れですか?
            </a>
          </div>
        </CardContent>
        <CardFooter>
          <Button className="w-full">ログイン</Button>
        </CardFooter>
      </Card>
    </div>
  )
}

shadcnでまだインストールされていないコンポーネントがあるので適宜追加しましょう。

npx shadcn@latest add checkbox
npx shadcn@latest add input
npx shadcn@latest add label
npx shadcn@latest add card

これでv0で自然言語で作成した画面をRailsに取り込むことができるようになりました。

Helloworld.tsx

import LoginForm from "./LoginForm";

export default function HelloWorld() {
  return <LoginForm />;
}

で表示します。

変な位置に配置されたので修正しましょう。

application.html.erb

  <body>
    <main class="container mx-auto px-5 flex justify-center">
      <%= yield %>
    </main>
  </body>

とりあえず中央には寄りましたが、application.html.erbで flex container を指定するより個々のReact Componentで制御するほうが柔軟で良いかもしれません。

あとはCardの幅とか「ログイン情報を記録する」と「パスワードをお忘れですか?」をちょちょっと手で修正するとこんな感じになります。

LoginForm.tsx

import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";

export default function LoginForm() {
  return (
    <div className="flex min-h-screen items-center justify-center p-4">
      <Card className="w-[400px]">
        <CardHeader>
          <CardTitle className="text-2xl">ログイン</CardTitle>
          <CardDescription>アカウントにログインしてください</CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="space-y-2">
            <Label htmlFor="email">メールアドレス</Label>
            <Input id="email" type="email" placeholder="example@example.com" />
          </div>
          <div className="space-y-2">
            <Label htmlFor="password">パスワード</Label>
            <Input id="password" type="password" />
          </div>
          <div className="flex justify-between flex-col">
            <div className="flex items-center space-x-2">
              <Checkbox id="remember" />
              <Label htmlFor="remember" className="text-sm">
                ログイン情報を記憶する
              </Label>
            </div>
            <a href="#" className="text-sm text-primary hover:underline mt-2">
              パスワードをお忘れですか?
            </a>
          </div>
        </CardContent>
        <CardFooter>
          <Button className="w-full">ログイン</Button>
        </CardFooter>
      </Card>
    </div>
  );
}

Enjoy Vibe Coding!!

メモ

  • gemのshadcn-uiだと React Component ではなく erbが出力される
  • erbを利用しない場合、gemの側の shadcn-uiは特に必要なかった
  • 「tailwindの最新版がv4なのにドキュメントがv3にしか対応してない...」ということで色々ハマったが今見たら更新されていたのでクリアできた

株式会社CodeKnightsは

「生成AI時代の、変化の激しい環境を勝ち残るためのWebサービス開発」

を専門として活動しています。

お仕事のお問い合わせはこちらから↓

https://www.codeknights.co.jp/contact

その他の人気記事

https://zenn.dev/yukito0616/articles/d3b7032e9f1e90

https://zenn.dev/yukito0616/articles/00ccc30b58e458

https://zenn.dev/yukito0616/articles/15aa27a4ed9dae

https://zenn.dev/yukito0616/articles/fa41ea2d0cb308

SNSアカウント

X(Twitter)
https://x.com/yohira_dev

note
https://note.com/yukito_ohira/

Discussion