Chuyển tới nội dung chính

Tích hợp Ant Design

Ant Design là một thư viện UI mạnh mẽ, dễ dùng, và khi kết hợp với Next.js sẽ giúp bạn xây dựng ứng dụng web nhanh chóng, đẹp mắt và tối ưu SEO.

Xem thêm tài liệu chính thức tại Ant Design.

Ẩn/Hiện mục lục

I. Ant Design là gì?

  • Ant Design (AntD) là một UI Design System được phát triển bởi Ant Financial.
  • Nó cung cấp bộ component phong phú như Button, Input, Form, Table, Modal, Layout… giúp lập trình viên xây dựng giao diện nhanh chóng và nhất quán.
  • AntD đặc biệt mạnh mẽ trong hệ sinh thái React, hỗ trợ tùy biến theme, responsive layout, và tối ưu trải nghiệm người dùng.
  • Đây là một trong những framework UI phổ biến nhất thế giới cho React.

II. Khởi tạo dự án Next.js

npx create-next-app antd-demo
cd antd-demo
npm run dev

Mở trình duyệt tại http://localhost:3000 để kiểm tra dự án Next.js đã chạy.

III. Cài đặt Ant Design

npm install antd

IV. Import component AntD

Ví dụ sử dụng Button trong src/app/page.tsx:

import { Button } from 'antd';

export default function Home() {
return (
<div>
<h1>Welcome to Next.js + AntD</h1>
<Button type="primary">Click Me</Button>
</div>
);
}

V. Thêm CSS của AntD

Trong Next.js 13+, bạn có thể import CSS trực tiếp trong src/app/layout.tsx:

import 'antd/dist/reset.css'; // hoặc 'antd/dist/antd.css' tùy phiên bản

VI. Tùy biến theme (tuỳ chọn)

AntD hỗ trợ CSS-in-JScustom theme. Bạn có thể cấu hình màu sắc, font, kích thước trong file theme.config.js hoặc sử dụng ConfigProvider:

import { ConfigProvider } from 'antd';

<ConfigProvider theme={{ token: { colorPrimary: '#1677ff' } }}>
<App />
</ConfigProvider>

:::tip Lưu ý khi tích hợp

  • Bundle size: AntD khá lớn, nên chỉ import component cần dùng để giảm dung lượng.
  • SSR (Server-Side Rendering): Next.js hỗ trợ SSR, AntD hoạt động tốt nhưng cần đảm bảo import CSS đúng cách để tránh lỗi style.
  • Responsive: Sử dụng Layout và Grid của AntD để tối ưu hiển thị trên mobile.

:::

IX. Thực hành

Tích hợp AntD tạo giao diện thêm mới bài viết.

1. Tạo file thêm bài viết

Tạo file src/app/dashboard/create-post/page.tsx
"use client"; // nếu dùng Next.js 13+ với App Router

import styles from "@/styles/app.module.scss";
import { Form, Input, Button } from "antd";

export default function AddPostForm() {
const [form] = Form.useForm();

const onFinish = (values: any) => {
console.log("Form values:", values);
// Ở đây bạn có thể gọi API để lưu bài viết
};

return (
<main className={styles.main}>
<h2>Thêm bài viết mới</h2>
<Form
form={form}
layout="vertical"
onFinish={onFinish}
>
{/* Tiêu đề */}
<Form.Item
label="Tiêu đề"
name="title"
rules={[{ required: true, message: "Vui lòng nhập tiêu đề!" }]}
>
<Input placeholder="Nhập tiêu đề bài viết" />
</Form.Item>

{/* Nội dung */}
<Form.Item
label="Nội dung"
name="content"
rules={[{ required: true, message: "Vui lòng nhập nội dung!" }]}
>
<Input.TextArea rows={6} placeholder="Nhập nội dung bài viết" />
</Form.Item>

{/* Nút submit */}
<Form.Item>
<Button type="primary" htmlType="submit">
Thêm bài viết
</Button>
</Form.Item>
</Form>
</main>
);
}

2. Sửa layout Dashboard

Sửa file src/app/dashboard/layout.tsx
'use client';

import styles from "../../styles/app.module.scss";
import { usePathname, useRouter } from "next/navigation";
import Link from "next/link";

export default function DashboardLayout({
children
}: {
children: React.ReactNode
}) {

const pathName = usePathname();
const router = useRouter();

const handleClick = () => {
router.push("/");
}
return (
<section>
<div className={styles.main}>
<Link
href="/dashboard"
className={pathName === "/dashboard" ? styles.active : ""}
>
Dashboard
</Link>
{" | "}
<Link
href="/dashboard/create-post/"
className={pathName === "/dashboard/create-post/" ? styles.active : ""}
>
Thêm mới bài viết
</Link>
</div>
<main>{children}</main>
<div className={styles.main}>
<button className={styles.btn} onClick={handleClick}>Back Home</button>
</div>
</section>
)
}

3. Sửa layout Home

Sửa file src/app/layout.tsx
import type { Metadata } from "next";
import "../styles/global.scss";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import 'antd/dist/reset.css'; // hoặc 'antd/dist/antd.css' tùy phiên bản

export const metadata: Metadata = {
title: "Welcome to Next.js",
description: "Learn Next.js step by step",
};

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

4. Sửa trang bài viết chi tiết

Sửa file src/app/dashboard/[id]/page.tsx
import styles from "@/styles/app.module.scss";

export default async function Detail({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const res = await fetch(
`http://10.196.61.148:3000/api/posts/${id}`
);
const data = await res.json();

return (
<main className={styles.main}>
<div className={`${styles.title} ${styles.titleSub}`}>Post {data.title}</div>
<div className={styles.description}>
<p>{data.body}</p>
</div>
</main>
);
}

5. Sửa Style

Sửa file src/styles/app.module.scss
.main {
max-width: 800px;
margin: 0 auto;
padding: 2rem;

a {
color: #333;
text-decoration: none;

&.active {
font-weight: bold;
color: #0070f3;
}
}
}

.title {
font-size: 2.1rem;
font-weight: bold;
margin-bottom: 1rem;

&Sub {
font-size: 1.2rem;
}
}

.description {
font-size: 1.2rem;
line-height: 1.6;
color: #555;
margin-bottom: 1rem;
}

.header {
background-color: #0070f3;
padding: 1rem;
color: white;
text-align: center;

h1 {
margin: 0 0 10px;
font-size: 2rem;
}

a {
margin: 0 0.5rem;
}

}

.footer {
background-color: #f1f1f1;
padding: 1rem;
text-align: center;
color: #333;
}

.btn {
background: none;
color: #005bb5;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;

&:hover {
text-decoration: underline;
}
}

.single {
padding: 10px 16px;
background: #eee;
display: block;
margin: 8px 0;
border-left: 8px solid #eee;

&:hover {
border-left: 8px solid #005bb5;
}

h3 {
margin: 0;
}
}