個人網頁開發
EP.06

HeroUI 元件庫
現成 UI 積木,快速建出美觀介面

Card、Button、Chip、Divider — 我的網頁所有 UI 元件都來自這裡,
安裝一次,直接拿來用

Joseph Chen

2024
5 min read
1.2k views

有了 React + Tailwind,你已經能做出任何樣式的頁面。但每次都要從零寫一個按鈕、一張卡片嗎?

這就是元件庫(Component Library)的價值:把常用的 UI 元件封裝好,直接引入使用。 HeroUI 是我選擇的元件庫,它基於 Tailwind CSS,設計美觀,和 Next.js 相容。

打開我任何一個 page.tsx,第一行 import 通常長這樣:

bash
import { Card, CardBody, Button, Chip, Divider } from '@heroui/react';

安裝與設定(只做一次)

Step 1:安裝套件

terminal
npm install @heroui/react framer-motion

HeroUI 依賴 framer-motion 做動畫,兩個都要裝。

Step 2:設定 tailwind.config.ts

tailwind.config.ts
import type { Config } from "tailwindcss";
const { heroui } = require("@heroui/react");

const config: Config = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
    // ↓ 必加:讓 Tailwind 掃描 HeroUI 的樣式
    "./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
  ],
  plugins: [
    heroui({
      themes: {
        light: {
          colors: {
            primary: {
              DEFAULT: "#006FEE",  // 自訂主題色(我用藍色)
              foreground: "#FFFFFF",
            },
          },
        },
      },
    }),
  ],
};
export default config;
⚠️
如果不加 HeroUI 的 content 路徑,Tailwind 不會掃描 HeroUI 的樣式,元件可能顯示出錯或沒有樣式。

Step 3:加入 Providers

HeroUI 需要一個 Provider 包住整個 App,才能讓主題、動畫等功能正常運作:

app/providers.tsx(新建這個檔案)
'use client';

import { HeroUIProvider } from '@heroui/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <HeroUIProvider>
      {children}
    </HeroUIProvider>
  );
}
app/layout.tsx — 把 Providers 包住 children
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>        {/* ← 包住全部 */}
          <Navbar />
          <main>{children}</main>
          <Footer />
        </Providers>
      </body>
    </html>
  );
}

Card — 最常用的容器

Card 是網頁裡最基本的「卡片容器」,有陰影、圓角,適合放各種資訊。

基本用法

bash
import { Card, CardBody } from '@heroui/react';

<Card>
  <CardBody>
    <p>這是卡片裡的內容</p>
  </CardBody>
</Card>

這是卡片裡的內容

isPressable + as={Link} — 可點擊的卡片連結

我的 blog 文章列表用的方式:

bash
<Card
  isPressable           // 加上 hover 按壓效果
  as={Link}            // 讓 Card 渲染成 <a> 連結
  href="/blog/post-1"  // 連結目標
  className="border-none shadow-sm hover:shadow-lg transition-all"
>
  <CardBody className="p-6">
    <h3>EP.01 — Two Sum</h3>
    <p>從暴力解到 HashMap 思維</p>
  </CardBody>
</Card>
💡
as prop 是 HeroUI 的強大功能:把元件渲染成其他 HTML 元素或 React 元件。as={ Link } 讓 Card 有 Link 的功能(可以導航),同時保有 Card 的樣式。

Button — 豐富的變體

HeroUI 的 Button 有很多 variant(變體)和 color(顏色),組合使用可以表達不同的視覺層級:

variant 變體

bash
<Button color="primary" variant="solid">送出</Button>
<Button color="primary" variant="flat">取消</Button>
<Button color="primary" variant="shadow">主要行動</Button>

常用 Props

Prop型別預設說明
colorstringdefaultprimary / secondary / success / warning / danger
variantstringsolidsolid / flat / bordered / light / shadow / ghost
sizestringmdsm / md / lg
radiusstringmdnone / sm / md / lg / full(圓角程度)
isIconOnlybooleanfalse只有圖示的方形按鈕
asComponentbutton渲染成其他元件,常用 as={'{'}Link{'}'}
startContentReactNode按鈕左側的圖示或元素
endContentReactNode按鈕右側的圖示或元素
我的網頁實際用法
// 主要行動按鈕(Resume)
<Button
  as={Link}
  href="/resume"
  color="primary"
  size="lg"
  className="font-bold px-8 shadow-lg"
  endContent={<ArrowRight size={20} />}
>
  View Resume
</Button>

// 圖示按鈕(書籤)
<Button isIconOnly variant="light" size="sm">
  <Bookmark size={18} />
</Button>

Chip — 標籤與分類

Chip 是小標籤,我用它來顯示文章分類、EP 編號、技術標籤等。

LeetCode 系列
Web Dev
Graph
External
🔥 Hot
EP.06
bash
<Chip color="primary" variant="flat">LeetCode 系列</Chip>
<Chip color="success" variant="dot">進行中</Chip>     {/* dot 在左邊顯示圓點 */}
<Chip size="sm" variant="flat" className="text-[10px] font-black uppercase">
  EP.06
</Chip>

Divider — 分隔線

最簡單的元件,就是一條水平線,用來分隔內容區塊:

bash
<Divider />                              {/* 完整寬度的線 */}
<Divider className="opacity-30" />      {/* 加透明度讓線更淡 */}
<Divider className="my-12 opacity-50" /> {/* 加垂直間距 */}

以下是 opacity-30 的效果:

以下是 opacity-80 的效果:

其他常用元件快速一覽

Link

語意化連結,可以 href 外部 URL 或內部路由,支援 target="_blank"

<Link href="/blog" color="primary">Blog</Link>

Avatar

用戶頭像,可顯示圖片或文字縮寫,有 size / radius / bordered 等 props

<Avatar src="/profile.png" size="lg" />

Skeleton

載入佔位效果(骨架屏),讓頁面在資料還沒載入時有預覽框架

<Skeleton className="w-32 h-4 rounded" />

Spinner

載入中的旋轉動畫

<Spinner color="primary" size="sm" />

Modal

彈出視窗,需搭配 useDisclosure Hook 控制開關

const {isOpen, onOpen, onClose} = useDisclosure()

Tabs

分頁切換,每個 Tab 有自己的內容

<Tabs><Tab key="1" title="A">...</Tab></Tabs>
完整的 HeroUI 文件和互動示例在 heroui.com/docs。每個元件都有「Playground」可以直接改 props 預覽效果,是學習 HeroUI 最快的方式。

HeroUI + Tailwind 混用

HeroUI 元件本身用 Tailwind 寫的,所以你可以在 HeroUI 元件上加 className 覆蓋或擴充樣式,兩者完全相容:

混用範例
// HeroUI 的 Chip 加上自訂 className
<Chip
  size="sm"
  variant="flat"
  color="primary"
  className="font-bold uppercase text-[10px] tracking-widest"  // ← Tailwind class
>
  LeetCode 系列
</Chip>

// HeroUI 的 Card 加上 hover 效果
<Card className="border-none shadow-sm hover:shadow-xl transition-all duration-300">
  <CardBody className="p-8 sm:p-10">
    ...
  </CardBody>
</Card>

這篇學到什麼

🧩元件庫 = 封裝好的 UI 積木,直接引入使用,省去從頭設計的時間
⚙️安裝三步驟:npm install → tailwind.config 加 content 路徑和 plugin → providers.tsx 包住 App
🃏Card + CardBody:最常用的容器,加 isPressable + as={"{Link}"} 就是可點擊的卡片連結
🔘Button:color × variant 組合出不同視覺層級,endContent 放圖示,as={"{Link}"} 導航用
🏷️Chip:小標籤,顯示分類、EP 編號、技術標籤
🎨HeroUI + Tailwind 可以自由混用,在 HeroUI 元件上加 className 覆蓋預設樣式
Web Dev
HeroUI
Component Library
Card
Button
EP.06