Xây dựng bộ Component Kits dễ dàng với Radix Primitives và Tailwind CSS trong Reactjs
- Published on
Table Of Content
- Lý do nên sử dụng Radix Primitive
- Demo tạo Popover Component
- Ưu điểm của Radix Primitive
- Kết hợp với Tailwind Css
Lý do nên sử dụng Radix Primitive
Khi bạn là một Frontend developer và bắt đầu một dự án mới, việc lựa chọn một thư viện UI có thể khiến bạn đau đầu. Đối với dự án thiết kế theo một thư viện cụ thể như Ant Design
hoặc Material UI
sẽ giúp bạn tiết kiệm thời gian và công sức. Bạn chỉ cần cài đặt thư viện và tùy chỉnh một chút về màu sắc là có thể bắt đầu sử dụng.
Nhưng nếu thiết kế của dự án không tuân theo một thư viện UI cụ thể thì bạn sẽ làm gì? Trong tình huống này, bạn sẽ phải tự tạo và tùy chỉnh các UI Components. Điều này có thể tốn thời gian và công sức đáng kể.
Đây là lúc Radix Primitive trở nên hữu dụng. Sử dụng Radix, bạn có thể tạo ra các component UI tuỳ chỉnh dựa trên thiết kế của designer. Điều này giúp bạn đảm bảo rằng giao diện của dự án phản ánh chính xác ý tưởng thiết kế mà bạn đã nhận được từ designer, mà không phải giới hạn bởi các quy tắc của thư viện UI cụ thể nào đó.
Chúng ta hãy cùng xem cách hoạt động của Radix Primitive
Demo tạo Popover Component
- Install component từ command line.
npm install @radix-ui/react-popover@latest -E
Tạo component popover với file name là Popover.tsx
với nội dung dưới đây
// Popover.tsx
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
const Popover = PopoverPrimitive.Root
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className="z-50 w-72 rounded-md border border-violet-400 text-violet-600 font-bold p-4 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
export { Popover, PopoverTrigger, PopoverContent }
Như vây là chúng ta đã tạo xong component Popover một cách nhanh chóng. Tạo file index.tsx
để sử dụng Popover Component như sau:
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/test-popover";
export default function Home() {
return (
<main className="min-h-screen flex flex-col">
<div className="w-full text-center">
<Popover>
<PopoverTrigger>Open</PopoverTrigger>
<PopoverContent>Place content for the popover here.</PopoverContent>
</Popover>
</div>
</main>
);
}
Chạy đoạn code trên chúng ta sẽ thu được kết quả:
Ưu điểm của Radix Primitive
Qua ví dụ trên chúng ta có thể thấy ngay được các ưu điểm của Radix Primitive:
1. Opened
Các component của Radix được thiết kế với tính mở rộng cao, có thể tuỳ chỉnh dễ dàng và có thể truy cập sâu vào từng thành phần nhỏ của component, chúng ta có thể bọc chúng và tự thêm event listeners, props, or refs, ...
2. Unstyled
Các component của Radix Primitive đều chưa có style, vì vậy việc thêm style tuỳ chỉnh rất dễ dàng dù bạn đang sử dụng vanilla CSS, CSS preprocessors hay CSS-in-JS libraries. ( có thể xem ví dụ ở trên )
3. Incremental adoption
Tất cả các component của Radix đều độc lập, chúng ta hoàn toàn có thể install chỉ những component cần thiết, giúp giảm JS bundle size của project.
> npm install @radix-ui/react-dialog
> npm install @radix-ui/react-dropdown-menu
> npm install @radix-ui/react-tooltip
Kết hợp với Tailwind CSS
Tailwind Css cũng không còn xa lạ với các lập trình viên Frontend, nó một thư viện CSS utility, được thiết kế để giúp bạn xây dựng giao diện người dùng nhanh chóng và dễ dàng bằng cách sử dụng các class CSS đã được định sẵn.
Ví dụ sử dụng class của tailwind:
<h1 class="text-3xl font-bold underline">
Hello world!
</h1>
Sẽ tương đương với:
<h1
style={{
fontSize: "1.875rem",
lineHeight: "2.25rem",
fontWeight: 700,
textDecoration: "underline",
}}
>
Hello world!
</h1>
Xem cách install Tailwind tại đây
Để tạo ra 1 bộ Component Kits consistent về style thì chúng ta sẽ phải định nghĩa các common style cho Project.
Ví dụ về định nghĩa colors và heading style cho Project:
Trong file index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl;
}
h2 {
@apply text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl;
}
h3 {
@apply text-3xl font-bold tracking-tight lg:text-4xl;
}
h4 {
@apply text-2xl font-bold md:text-3xl;
}
h5 {
@apply text-xl font-bold md:text-2xl;
}
h6 {
@apply text-lg font-bold md:text-xl;
}
:root {
--background: 240 80% 98%; /* Màu nền - Màu xám nhạt và rất sáng */
--foreground: 0 0% 20%; /* Màu chữ nền - Màu đen */
--muted: 240 20% 96%; /* Màu nhạt - Màu xám nhạt và sáng */
--muted-foreground: 0 0% 40%; /* Màu chữ nền cho màu nhạt - Màu đen */
--primary: 210 40% 50%; /* Màu chính - Màu xanh lam nhạt */
--primary-foreground: 0 0% 100%; /* Màu chữ nền cho màu chính - Màu trắng */
--secondary: 30 100% 60%; /* Màu phụ - Màu cam sáng */
--secondary-foreground: 0 0% 20%; /* Màu chữ nền cho màu phụ - Màu đen */
--accent: 45 100% 60%; /* Màu điểm nhấn - Màu vàng sáng */
--accent-foreground: 0 0% 10%; /* Màu chữ nền cho màu điểm nhấn - Màu đen */
--destructive: 0 100% 50%; /* Màu hủy bỏ - Màu đỏ sáng */
--destructive-foreground: 210 40% 98%; /* Màu chữ nền cho màu hủy bỏ - Màu xanh lam nhạt */
}
}
Bên trên mình định nghĩa theo hệ màu hsl, để có thể sử dụng được các mã màu trên với tailwind chúng ta sẽ sửa file tailwind.config.ts
như sau:
// tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
colors: {
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
},
},
},
plugins: [],
};
export default config;
Vậy là chúng ta đã config các biến global colors cho tailwind css và overide lại style cho thẻ Heading. Giờ hãy cùng thử sử dụng tailwind với các biến ở trên:
Thêm border-primary
, text-primary
cho PopoverPrimitive.Content
// Popover.tsx
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className="z-50 w-72 rounded-md border border-primary text-primary font-bold p-4 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
{...props}
/>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent };
Test các thẻ Heading và Popover sau khi thêm custom style tailwind:
// index.tsx
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/test-popover";
export default function Home() {
return (
<div className="min-h-screen flex flex-col bg-background">
<div className="w-full text-center">
<h1 className="text-primary">This is Heading 1 primary</h1>
<h2 className="text-secondary">This is Heading 2 secondary </h2>
<h3 className="text-muted-foreground">This is Heading 3 muted</h3>
<h4 className="text-accent">This is Heading 4 accent</h4>
<h5 className="text-destructive">This is Heading 5 destructive</h5>
<div className="mt-20">
<Popover>
<PopoverTrigger>
<h5>Open</h5>
</PopoverTrigger>
<PopoverContent>Place content for the popover here.</PopoverContent>
</Popover>
</div>
</div>
</div>
);
}
Chúng ta có được kết quả như sau:
Conclusion
Vậy là chúng ta đã thành công sử dụng Radix Primitive và Tailwind CSS để tạo ra một customize Popover component và định nghĩa các common style cho các thẻ Heading, colors trong tailwind để dùng cho dự án. Từ đây bạn có thể tạo thêm nhiều customize component khác phù hợp với yêu cầu của dự án. Với cách trên, chúng ta có thể tạo ra 1 bộ component kits nhanh chóng và vẫn có thể đảm bảo được UI như theo designer thiết kế.