💫

Next.js プロジェクトで NextUI を使用してみた

2024/04/29に公開

はじめに

https://nextui.org/
Next.js を用いて個人開発を進める中で、Tailwind CSS をベースとした UI ライブラリを探していたところ、NextUI という UI ライブラリを見つけました。NextUI の UI コンポーネントは 他の Tailwind CSS ベースのものと比較して、中々イケてそうに見えたので、使用してみることにしました。
簡単なレイアウトを作成してみて、良かった点などを紹介できればと思います。

NextUI の導入

今回は作成済みの Next.js(App Router) プロジェクトに NextUI を導入していきたいと思います。

インストール

以下のコマンドを実行して NextUI をインストールします。

npm install @nextui-org/react Framer-motion

セットアップ

tailwind.config.ts に設定を追加

次に tailwind.config.tsに以下のコードを追記。

tailwind.config.ts
const config = {
  content: [
    // ...
    "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
  ],
  theme: {
    extend: {},
  },
  darkMode: "class",
  plugins: [nextui()]
}

export default config;

Provider でラップする

app/porviders.tsxを作成し、以下を記載する。

app/providers.tsx
'use client'

import { NextUIProvider } from '@nextui-org/react'

export const Providers = ({ children }: { children: React.ReactNode }) => {
  return (
    <NextUIProvider>
      {children}
    </NextUIProvider>
  )
}

そしてapp/layout.tsxで、Providers をインポートしラップする。

app/layout.tsx
import { Providers } from "./providers"

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Providers>
         {children}
        </Providers>
      </body>
    </html>
  );
}

以上で Next UI のセットアップが完了しました。
最後にコンポーネントが正常に表示されるかを確認してみましょう。

以下のようにapp/page.tsxで、 Button コンポーネントを呼び出し、ボタンが表示されることを確認できたら、完了です。

app/page.tsx
export default function Home() {
  return (
    <>
      <Button color="primary">クリック</Button>
    </>
  )
}

良い点と辛い点

NextUI を使ってみた感想

コード
app/page.tsx
import { Main } from "./components/main";
import { Header } from "./components/header";

export default function Home() {
  return (
    <>
      <Header />
      <Main />
    </>
  )
}

app/components/header.tsx
import {Button, Input, Link, Navbar, NavbarBrand, NavbarContent, NavbarItem} from "@nextui-org/react";
import { SearchIcon } from "./SearchIcon";

export const Header = () => {
  return (
    <Navbar className="border-b-2 border-gray-280" classNames={{wrapper: "max-w-full"}}>
      <NavbarBrand>
        <p className="font-bold text-inherit text-3xl">MYTTY</p>
      </NavbarBrand>
      <div className="w-[640px] sm:visible invisible">
        <Input
          isClearable
          radius="sm"
          placeholder="キーワードで検索"
          startContent={
            <SearchIcon className="text-black/50 mb-0.5 text-slate-400 pointer-events-none" />
          }
        />
      </div>
      <div className="visible sm:invisible">
        <SearchIcon className="text-black mb-0.5 text-slate-600 pointer-events-none" />
      </div>
      <NavbarContent justify="end">
        <NavbarItem>
          <Link href="#" className="text-black/50 hover:opacity-100 hover:text-black font-bold" >
            ログイン
          </Link>
        </NavbarItem>
        <NavbarItem>
          <Button color="primary" radius="sm" className="font-bold" >
            会員登録
          </Button>
        </NavbarItem>
      </NavbarContent>
    </Navbar>
  )
}

app/components/main.tsx
import { Card, CardBody, CardFooter, Image } from "@nextui-org/react"

type Item = {
  title: string
  name: string
  img: string
}

export const Main = () => {
  const items = Array(10).fill({
    title: "カワセミ",
    name: "kawasemi",
    img: "/kawasemi.jpg"
  });

  return (
  <div className="flex justify-center mt-8">
    <div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
      {items.map((item: Item, index) => (
        <Card key={index}>
          <CardBody>
            <Image
              src={item.img}
              alt={item.name}
              height={200}
              width={200}
            />
          </CardBody>
          <CardFooter className="font-bold">
            <p>{item.title}</p>
          </CardFooter>
        </Card>
      ))}
    </div>
    </div>
  )
}

NextUI を利用して簡単なレイアウトを実装してみました。上記のレイアウトは1時間ほどで作成したものになります。実際に NextUI を利用してみていいと感じた点もありましたが、つらいと感じた点もあったので、個人的な感想ですが、まとめておきます。

よかった点

アニメーションを簡単に無効化することが可能

NextUI は様々なコンポーネントにおいて、アニメーションなどが標準で実装されていますが、アニメーションを無効化したい場合もあるかと思います。
NextUIのコンポーネントは、簡単にアニメーションを無効化できるように設計されています。
ボタンを例に挙げると、以下のようにクリックした際に波紋が広がるような演出があります。

ボタンの場合だと以下のように、propsとしてdisabledRipple="true"を渡してあげるだけで、アニメーションを無効化することが可能です。

<Button disableRipple="true" color="primary">
  クリック
</Button>

コンポーネントの種類が豊富

コンポーネントの種類が多いと感じました。(2024/04/29 日時点では、44個のコンポーネントが存在)
大体のコンポーネントが揃っているので、個人開発などで利用する場合は NextUI で十分なほどです。
最近ではカレンダーコンポーネントであったり、 DatePicker コンポーネントが追加されるなど、コンポーネントが続々と追加されているので、この先さらにコンポーネントの種類が増えていくと思います。

ドキュメントが充実している

コンポーネントごとに、仕様が細かく書かれていたり、使用例もたくさん紹介されているため充実しています。カスタマイズ方法に関しても、詳しく書いてあるので、非常にありがたいです。

つらかった点

スタイルを上書きするコストが高い

スタイルを上書きする際のコストが高いと感じました。

簡単なレイアウトを作成する際に、ブランド名と会員登録ボタンを両端に配置したかったのですが、Navbar コンポーネントでは、意図しないスタイルがデフォルトであたっていたためそのまま使用すると、以下のように両端に空白ができていました。

export const Header = () => {
  return (
    <>
      <Navbar className="border-b-2 borer-gray-200">
        ...
      </Navbar>
    </>
  )

スタイルを確認すると、<header>タグに maxWidth がデフォルトで効いていたのが原因だったため、これを上書きする必要があります。

NavBar コンポーネントにスタイルを当ててしまうと、<nav>タグに対してスタイルが当たってしまいます。調査したところ、NavBar コンポーネントの classNames というプロップスに、キーとスタイルを指定すれば、NavBar コンポーネントを構成する要素に対してスタイルを当てることが可能であるとわかりましたが、キーがあまり直感的ではなかったため、NextUI のソースコードを確認する必要がありました。

コードを以下のように修正し、<header>タグのスタイルを上書きすることに成功しましたが、ソースコードを確認しにいく必要があるなど、スタイルの上書きが大変でした。

export const Header = () => {
  return (
    <>
      <Navbar className="border-b-2 borer-gray-200" classNames={{wrapper: "max-w-full"}}>
        ...
      </Navbar>
    </>
  )

まとめ

NextUI を試してみてつらい点もありましたが、十分使う価値があると感じました。
UI コンポーネントのデフォルトのデザインに関しては、他の UI ライブラリと比較してかなり優れていると思うので、ポートフォリオの作成であったり、個人開発の際には活躍すると思います。
ぜひ皆さんも NextUI を利用してみてください!

Discussion