はじめに
shadcn/uiを使い始めてから、UIライブラリに対する考え方がガラッと変わったんですよ。コピペで使える、カスタマイズ自由、依存関係に縛られない。これが現代的なUIライブラリのあり方だと思っていました。
で、最近見つけたのがReUI。GitHubで2,200スター以上、shadcn/uiとの相性を意識して作られているという話を聞いて試してみたんですけど、これがまた良い。
特にアニメーション周り。shadcn/uiにMotion(旧Framer Motion)を組み合わせた感じで、標準でヌルヌル動くコンポーネントが揃っています。30代になって思うのは、「見た目の美しさ」と「使い心地の良さ」は別物だということ。ReUIは両方を押さえている印象です。
ReUIとは
ReUIは、React、TypeScript、Tailwind CSS、Motionで構築されたオープンソースのUIコンポーネント集です。shadcn/uiと同じく、コードをコピーして自分のプロジェクトに持ってくるスタイル。
公式サイトでは「Open-source collection of UI components and animated effects built with React, TypeScript, Tailwind CSS, and Motion」と説明されています。
特徴的なのは、Radix UIとBase UIの両方に対応していること。同じコンポーネントでも、好みの基盤を選べる設計になっています。
現在MITライセンスで公開されていて、16人以上のコントリビューターが開発に参加中。最終更新も数日前と、活発にメンテナンスされています。
特徴・メリット
1. アニメーションが標準装備
これがReUIの最大の強み。Motion(Framer Motion)が組み込まれているので、追加の設定なしでアニメーション付きのコンポーネントが使えます。
マーキー、タイピングテキスト、グラデーション背景など、「あると嬉しいけど自分で作るのは面倒」な演出効果も揃っている。正直なところ、この手のアニメーションを一から実装すると結構時間かかるんですよね。
2. shadcn/uiとの完璧な互換性
既存のshadcn/uiプロジェクトに追加で導入できる設計。Tailwind CSSのCSS変数を共有するので、テーマの一貫性も保てます。
個人的には、この「既存資産を活かせる」という点が一番の決め手でした。新しいライブラリを入れるたびにゼロから学び直すのは、30代にはキツい。
3. Propsベースで扱いやすい
「AI最適化設計」を謳っているだけあって、Propsの構造がきれいに整理されています。過度なTailwindクラスの羅列がなく、variant、size、modeなどの直感的なPropsで制御できる。
これ、意外と重要なんですよ。Tailwindのクラス名を大量に書くより、Propsで指定する方がコードの見通しが良くなる。
4. Radix UIとBase UIの両対応
同じボタンでも、Radix UIベースとBase UIベースの2種類が用意されています。
- Radix UI版: スタイル付きですぐ使える
- Base UI版: アンスタイルで自由にカスタマイズ
プロジェクトの方針に合わせて選べるのは嬉しい。コスパ的に、両方試して合う方を選べる設計は親切です。
5. 豊富なコンポーネント
Accordion、Alert、Avatar、Badge、Button、Calendar、Card、Chart、Dialog、Data Grid、Form、Navigation Menu、Tabs、Tooltipなど、業務アプリで必要になるUIパーツはほぼ揃っています。
特にData Gridは、TanStack Tableとの連携を前提に作られていて実用的。
インストール方法
前提条件
ReUIを使うには、以下の環境が必要です:
- React 19以上
- TypeScript 5.7以上
- Tailwind CSS 4以上
- Radix UI 1以上(Radix版を使う場合)
- Base UI 1以上(Base UI版を使う場合)
- Motion 12.19以上
React 19とTailwind CSS v4という最新スタックを前提にしているので、新規プロジェクト向けですね。
必須パッケージのインストール
# Radix UI
npm i radix-ui
# Base UI(Base UI版を使う場合)
npm i @base-ui-components/react
# Motion(アニメーション用)
npm i motion
# Lucide Icons
npm i lucide-react
# Remix Icons(オプション)
npm i @remixicon/react
globals.cssの設定
@import 'tailwindcss';
@import 'tw-animate-css';
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
/* ...その他の変数 */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ...ダークモード用の変数 */
}
レイアウトの設定
Base UIのポップアップコンポーネントが正しく表示されるよう、ルートにisolateクラスを追加します。
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja">
<body className="isolate">
{children}
</body>
</html>
)
}
基本的な使い方
Buttonコンポーネント
import { Button } from '@/components/ui/button';
export default function ButtonDemo() {
return (
<div className="flex gap-4">
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="mono">Mono</Button>
<Button variant="outline">Outline</Button>
<Button variant="dashed">Dashed</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Destructive</Button>
</div>
);
}
variantのバリエーションが豊富なのが良い。dashedなんて、意外と使う場面あるんですよね。
サイズとシェイプ
// サイズ指定
<Button size="xxs">Extra Small</Button>
<Button size="xs">Small</Button>
<Button size="sm">Medium Small</Button>
<Button size="md">Medium</Button>
// 円形ボタン
<Button shape="circle" mode="icon">
<PlusIcon />
</Button>
// 角丸の調整
<Button radius="full">Rounded Full</Button>
アイコン付きボタン
import { Button } from '@/components/ui/button';
import { Mail, Loader2 } from 'lucide-react';
// アイコン付き
<Button>
<Mail className="mr-2 h-4 w-4" />
メールで送信
</Button>
// ローディング状態
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
送信中...
</Button>
asChildでカスタム要素に
import { Button } from '@/components/ui/button';
import Link from 'next/link';
<Button asChild>
<Link href="/about">詳細を見る</Link>
</Button>
Radix UIのSlotを使っているので、asChildでリンクやカスタムコンポーネントにスタイルを適用できます。
実践的なユースケース
アニメーション付きセクション
ReUIの真価は、アニメーションコンポーネントとの組み合わせにあります。
import { AnimatedSection } from '@/components/ui/animated-section';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
export default function FeatureSection() {
return (
<AnimatedSection animation="fadeInUp" delay={0.2}>
<Card>
<CardHeader>
<CardTitle>高速な開発体験</CardTitle>
</CardHeader>
<CardContent>
<p>コピペで使えるコンポーネントで、開発速度が向上します。</p>
</CardContent>
</Card>
</AnimatedSection>
);
}
スクロールに連動したフェードインなど、よくある演出が簡単に実現できる。
フォームとバリデーション
React Hook FormとZodとの組み合わせが推奨されています。
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
const schema = z.object({
name: z.string().min(1, "名前を入力してください"),
email: z.string().email("有効なメールアドレスを入力してください"),
})
export function ContactForm() {
const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: { name: "", email: "" },
})
const onSubmit = (data: z.infer<typeof schema>) => {
console.log(data)
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>お名前</FormLabel>
<FormControl>
<Input placeholder="山田太郎" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>メールアドレス</FormLabel>
<FormControl>
<Input placeholder="email@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">送信</Button>
</form>
</Form>
)
}
Data Gridでテーブル表示
TanStack Tableをベースにした高機能なテーブルコンポーネントも用意されています。
import { DataGrid } from '@/components/ui/data-grid';
const columns = [
{ accessorKey: 'name', header: '名前' },
{ accessorKey: 'email', header: 'メールアドレス' },
{ accessorKey: 'role', header: '役割' },
];
const data = [
{ name: '田中一郎', email: 'tanaka@example.com', role: '管理者' },
{ name: '佐藤花子', email: 'sato@example.com', role: 'メンバー' },
];
export function UserTable() {
return <DataGrid columns={columns} data={data} />;
}
ソート、フィルタ、ページネーションなどの機能が組み込まれているので、業務アプリのテーブル実装が楽になります。
shadcn/uiとの違い
正直なところ、ReUIはshadcn/uiの「拡張版」という位置づけです。
| 項目 | ReUI | shadcn/ui |
|---|---|---|
| アニメーション | Motion統合で標準対応 | 別途追加が必要 |
| 基盤 | Radix UI + Base UI | Radix UI |
| Tailwind | v4前提 | v3.4以上 |
| React | 19前提 | 18以上 |
| コンセプト | アニメーション重視 | シンプル重視 |
新規プロジェクトでアニメーション付きのモダンなUIを作りたいならReUI、既存プロジェクトへの導入やシンプルさ重視ならshadcn/ui、という使い分けが良さそう。
両方併用することも可能なので、「基本はshadcn/ui、アニメーションが欲しい部分だけReUI」という組み合わせもアリですね。
まとめ
ReUIを導入して感じた変化:
- アニメーション実装: 自分で書かなくて良くなった
- 開発速度: 見た目の調整時間が大幅に減った
- コード品質: Propsベースで読みやすくなった
- 保守性: shadcn/uiと同じくカスタマイズ自由
- 学習コスト: shadcn/ui経験者ならほぼゼロ
個人的には、新規のNext.jsプロジェクトで「ちょっとリッチなUI」を作りたいときに最適だと思います。React 19 + Tailwind CSS v4という最新スタックを前提にしているので、レガシーな環境には向かないですが、新しく始めるなら選択肢に入れる価値はあります。
特に「アニメーションを入れたいけど、自分で実装するのは面倒」という人には刺さるはず。まだ試していない人は、公式サイトのコンポーネント一覧を見てみてください。動きのあるデモを見ると、「あ、これ使いたい」となると思いますよ。
