Tìm hiểu cách prompt để có UI nhất quán trong ứng dụng React bằng design tokens và quy tắc component để màn hình do AI tạo khớp về spacing, typography và form.

Sự không nhất quán trong UI thường xuất hiện ở những chi tiết nhỏ khiến cảm giác không liền mạch khi bạn tương tác. Một trang có padding rộng rãi, trang khác thì chật chội. Các heading nhảy kích thước, nút đổi hình dạng và màu sắc, và cùng một input hành xử khác nhau tuỳ màn hình.
Phần lớn, sự drift đến từ vài điều cơ bản:
Điều này thường xảy ra khi các màn hình được tạo từ các prompt riêng lẻ. Mỗi prompt về cơ bản là một khởi đầu mới, nên mô hình tự điền các quyết định còn thiếu bằng cách phỏng đoán. Ngay cả “dùng kiểu hiện đại” vẫn bỏ lại hàng trăm lựa chọn nhỏ: gap 8px hay 12px, chữ thân 14px hay 16px, khi nào hiển thị lỗi, nút chính trông như thế nào.
Bạn có thể chỉnh tay hai hay ba trang, nhưng điều đó không thể mở rộng. Bạn sẽ chạy theo các chỉnh sửa CSS lẻ tẻ, copy style giữa các file, và sửa lại form nhiều lần. Các quy tắc chỉ nằm trong đầu bạn, chứ không nằm trong dự án.
Hãy tưởng tượng bạn tạo màn hình đăng nhập hôm nay và màn hình hồ sơ ngày mai. Nếu một màn hình chỉ hiển thị lỗi khi submit nhưng màn kia hiển thị khi blur, người dùng sẽ nhận ra. Nếu chiều cao nút chính đổi giữa các màn hình, app có cảm giác bị may vá.
Sự nhất quán trở thành mặc định khi mọi màn hình tuân theo cùng một hệ thống chia sẻ: design tokens (spacing, type, màu) cộng với một tập nhỏ quy tắc cho component và form.
Design tokens là các giá trị đặt tên đơn giản bạn dùng lại khắp UI. Thay vì yêu cầu “padding thoải mái” cho mỗi màn hình, bạn dùng token như space-4. Thay vì “bo tròn nhẹ”, bạn dùng radius-md. Tên token ổn định ngay cả khi bạn thay đổi ánh xạ của nó sau này.
Token là tập các quyết định bạn muốn mọi màn hình chia sẻ. Chúng loại bỏ sở thích cá nhân và phỏng đoán—chính là nguyên nhân gây drift khi bạn tạo hoặc xây dựng trang mới.
Token điển hình bao phủ spacing, typography, màu sắc, hình dạng và một chút elevation. Lợi ích là thiết thực: header luôn dùng cùng kích thước, card luôn có cùng padding, và nút chính giữ cùng màu và radius.
Token hóa những thứ ảnh hưởng đến cảm nhận tổng thể sản phẩm: thang spacing, kích thước font và line-height, màu cốt lõi (text, background, primary, danger, border), và một tập nhỏ border radius.
Giữ những lựa chọn phụ thuộc nội dung linh hoạt, như độ dài copy, icon dùng, hoặc một section cần hai hay ba card.
Khi bạn tạo màn hình (kể cả với công cụ như Koder.ai), đưa một bộ token nhỏ ở đầu sẽ giảm phỏng đoán và khiến đầu ra đồng nhất hơn rõ rệt.
Bộ token chỉ là một menu ngắn các giá trị được phép. Nhỏ hơn tốt hơn vì còn ít chỗ cho lựa chọn ngẫu nhiên, nhưng vẫn cần bao phủ những thứ cơ bản làm màn hình trông lệch.
Bắt đầu với spacing. Chọn một thang và dùng nó khắp nơi cho padding, gap và layout. Một tập như 4, 8, 12, 16, 24, 32 đáp ứng hầu hết UI. Nếu thiết kế cần 10px hoặc 18px, làm tròn về token gần nhất thay vì thêm số mới.
Rồi định nghĩa mặc định typography để heading và body không drift. Bạn không cần hệ thống chữ khổng lồ. Bạn cần các bước rõ ràng và lặp lại được.
Một bộ gọn mà vẫn hữu dụng:
Truy cập (accessibility) cũng thuộc hệ thống. Định nghĩa kiểu outline khi focus (màu, độ dày, offset) để người dùng bàn phím có trạng thái focus nhất quán. Đặt kích thước mục tiêu chạm tối thiểu (như 44x44) cho mobile. Giới hạn màu chữ vào một bộ nhỏ, đáng tin cậy để giữ độ tương phản dự đoán được.
Nếu nút có vẻ chật là do một màn hình dùng padding 10 và màn khác dùng 12. Với token, bạn có thể nói: “Nút dùng paddingY=8, paddingX=16, radius=12, token outline cho focus, min height 44.” Khi những số đó cố định, bộ sinh ngừng ứng biến.
Token thiết lập con số. Quy tắc component thiết lập thói quen.
Chọn một tập nhỏ component cốt lõi và coi chúng là thành phần xây dựng duy nhất cho màn hình. Giữ chúng đơn giản và tái sử dụng: Button, Input, Select, Checkbox, Card. Bạn có thể thêm TextArea và Modal, nhưng chúng phải theo cùng hệ thống (nhãn, spacing, trạng thái).
Tiếp theo, giới hạn variant và định nghĩa khi nào được phép dùng. Ví dụ: Button có primary, secondary và danger. Primary dùng cho hành động chính trên màn hình (thường chỉ một). Secondary cho huỷ hoặc hành động ưu tiên thấp. Danger chỉ cho hành động phá huỷ như xóa. Nếu một variant không thể biện minh, mặc định về secondary.
Quy tắc spacing ngăn drift tinh vi. Định nghĩa mặc định bên trong component: padding Button, chiều cao Input, khoảng cách nhãn-đến-field, khoảng cách chuẩn giữa các trường xếp chồng. Thêm vài quy tắc layout nữa: Card có padding nội bộ cố định và spacing header/body nhất quán; Modal dùng cùng các bước chiều rộng và căn footer giống nhau.
Cuối cùng, làm cho trạng thái trở nên không thương lượng vì đây thường là nơi UI bắt đầu trông ngẫu nhiên:
Khi bạn tạo một màn hình nặng form như “Create project”, những quy tắc này ngăn kích thước nút lẫn lộn, vị trí nhãn thay đổi, hay một “card đặc biệt” chỉ xuất hiện ở một trang.
Ngay cả khi nhìn ổn, nhiều phàn nàn “có cảm giác sai” đến từ hành vi form. Nếu mỗi màn hình xử lý nhãn, lỗi và focus khác nhau, người dùng sẽ cảm nhận sự không nhất quán.
Chọn một mẫu form và dùng nó khắp nơi: nhãn, dấu optional/required, helper text, rồi error text. Giữ ngôn ngữ nhất quán (ví dụ, nhãn chữ thường câu, helper text ngắn, và lỗi bắt đầu bằng động từ).
Những quy tắc tránh hầu hết drift:
Khóa kích thước và layout để màn hình không “thở” khác nhau. Định nghĩa một chiều cao input, một chiều cao nút và chiều rộng trường mặc định. Trên desktop, căn các trường theo grid nhất quán và xếp nhãn trên input. Trên mobile, làm trường full width và tránh form hai cột trừ khi thật sự cần.
Ví dụ đơn giản: màn hình “Create project” có Name, Region và Description. Dù Region là select, vẫn đối xử như trường khác: cùng chiều cao, cùng vị trí nhãn, cùng dòng lỗi. Nếu người dùng submit với Name rỗng, focus chuyển đến Name, lỗi xuất hiện dưới nó, và layout giữ ổn định.
Nếu bạn tạo màn hình trong Koder.ai, đặt những quy tắc form này vào prompt một lần và tái sử dụng khắp nơi để mỗi form mới hành xử giống nhau mà không cần dọn dẹp lặp lại.
Coi prompt như một hợp đồng UI nhỏ. Giữ nó ngắn, cụ thể và có thể tái sử dụng để mỗi màn hình mới bám vào cùng spacing, typography, component và hành vi.
Một mẫu thực dụng là dán một spec UI gọn lên đầu yêu cầu, rồi mô tả màn hình bằng ngôn ngữ thường.
UI SPEC (apply to every screen)
Tokens:
- Spacing: 4, 8, 12, 16, 24, 32
- Radius: 8
- Typography: H1 24/32, H2 18/26, Body 14/20
- Colors: text, muted, bg, primary, danger (no custom hex)
Components (must use): PageShell, Section, Card, Button, Input, Select, TextArea, FormRow, HelperText, Toast
Layout rules:
- Page padding: 24 desktop, 16 mobile
- Section spacing: 24
- Card padding: 16
- Grid: 12 cols desktop, 4 cols mobile, gap 16
Do:
- Reuse components and tokens only
- Keep labels above inputs, helper text below
Do not:
- Invent new spacing values, font sizes, or one-off CSS
- Mix different button heights or input styles
If a new component is needed:
- Extend an existing component pattern and document it in the output
- Do not create new visual styles outside tokens
Sau spec, thêm vài kiểm tra chấp nhận (acceptance checks) để phát hiện drift sớm:
Nếu bạn dùng generator chat, giữ spec này ổn định giữa các yêu cầu. Thay đổi nó mỗi lần sẽ làm mất tác dụng.
Viết hợp đồng UI trước khi tạo bất cứ thứ gì: một bộ token nhỏ (spacing, type, màu, radius, shadow) cộng danh mục component ngắn (Button, Input, Select, Card, Modal, Table, Toast). Nếu thiếu token hay component, mô hình sẽ tự nghĩ ra và UI sẽ drift.
Rồi tạo một màn hình tham chiếu khai thác các quy tắc. Một trang nhiều form là bài test tốt vì nó có header, helper text, lỗi validation, nút primary/secondary và toast thành công. Xử lý màn hình đó như baseline.
Từ baseline, xây các màn hình mới bằng cách ghép các thứ đã định nghĩa. Đừng yêu cầu “styling mới”. Hãy yêu cầu cùng Card, cùng thang spacing, cùng bước typography, và cùng mẫu trường.
Một quy trình đơn giản:
Nếu một màn hình “Search users” có spacing chặt hơn tham chiếu, đừng chỉnh margin thủ công. Cập nhật spacing token hoặc quy tắc Card một lần, rồi sinh lại.
Nếu bạn làm việc trong Koder.ai, snapshots và rollback hữu ích: khoá baseline, thử nghiệm an toàn, và revert nhanh khi một thay đổi bắt đầu gây drift.
Cách nhanh nhất để mất nhất quán là coi token và quy tắc như gợi ý. Ngoại lệ nhỏ nhân lên qua các màn hình mới.
Một bẫy phổ biến là thay đổi thang spacing giữa dự án. Màn hình đầu dùng 8, 16, 24. Một màn hình sau thêm 10 và 18 “vì trông đúng”. Giờ drift được cho phép, và các màn hình cũ không bao giờ được cập nhật.
Nguồn drift khác là để generator phát minh style component mới. Nếu bạn không nói “chỉ có những variant nút này”, nó có thể tạo radius mới hoặc padding input khác cho một màn hình.
Trạng thái cũng thường bị bỏ sót. Loading, empty, và error thường thay đổi spacing và hành vi. Nếu thêm chúng vào cuối, bạn thường có các pattern vội vàng không khớp.
Cũng chú ý đến loại mô tả mơ hồ: “làm nó hiện đại với bóng mềm” thì mơ hồ, trong khi các quy tắc hành vi như “lỗi hiển thị dưới trường”, “nút disabled vẫn giữ focus styles”, và “Enter chỉ submit trên trường cuối” là cụ thể và lặp lại được.
Nếu bạn muốn một khối guardrail nhẹ để dán vào prompt, giữ nó ngắn:
Trước khi merge màn hình tạo ra, làm một quét hai phút.
Bắt đầu với spacing. Tìm các giá trị ngẫu nhiên như 13px hoặc margin một-off được thêm “chỉ để vừa”. Nếu dùng token, mọi gap phải đến từ bộ đã duyệt, bao gồm gutter, padding card, và khoảng cách giữa trường form.
Rồi kiểm tra typography theo thang chữ. Heading nên giảm kích thước theo quy tắc. Body không đổi kích thước giữa các section tương tự. Line height cũng quan trọng, đặc biệt ở các màn hình dày thông tin như trang cài đặt.
Quét nút tiếp theo. Variant và kích thước nên theo quy tắc: primary cho hành động chính, secondary cho hành động ít quan trọng, danger chỉ khi thật sự xóa. Chiều cao nút, vị trí icon, và kiểu label phải khớp.
Với form, nhất quán chủ yếu là cấu trúc. Nhãn ở một vị trí, dấu required theo một quy tắc, helper text và lỗi không tranh chỗ nhau, và lỗi xuất hiện ở vị trí nhất quán.
Checklist ngắn:
Cuối cùng, làm một pass mobile nhanh. Thu nhỏ chiều rộng và xác nhận layout thích ứng mà không phát minh kích thước font hay spacing mới.
Hãy tưởng tượng một flow onboarding đơn giản: ba màn hình (Profile, Preferences, Confirm), cộng một trang Settings sau đó. Bạn muốn mỗi màn hình cảm giác như cùng một designer tạo, dù chúng được sinh ở các lần khác nhau.
Trước khi tạo, cung cấp một bộ token nhỏ và vài quy tắc component:
TOKENS
- spacing: xs=4, sm=8, md=12, lg=16, xl=24
- radius: sm=8, md=12
- type: body=14/20, title=20/28, label=12/16
- layout: pageMax=960, sectionGap=24, fieldGap=12
COMPONENT RULES
- Page: max width=pageMax, padding=xl, sectionGap between blocks
- Card: padding=lg, radius=md
- Field: label above, helper below, fieldGap between fields
- Button row: primary on right, gap=sm
- Errors: shown under field, same copy style, no alerts
Bây giờ tạo “Profile” và “Preferences” riêng biệt. Vì cả hai màn hình phải dùng Page, Card, Field, và Button row như đã định, chúng sẽ có cùng margin, spacing nhãn và vị trí nút. Bước Confirm vẫn phù hợp, dù chứa nhiều text read-only hơn.
Hành vi form là nơi drift hay len lỏi, nên định nghĩa nó một lần và tái dùng: submit disable cho đến khi hợp lệ, lỗi inline chỉ sau blur hoặc submit, Enter chỉ submit ở bước cuối, và nút Back không xoá giá trị đã nhập.
Khi cần phần UI mới, đừng để mô hình tùy biến. Thêm một quy tắc rồi sinh lại với ý tái sử dụng:
Biến token và quy tắc thành một spec tái sử dụng bạn thật sự dùng. Nếu quá dài để dán, nó sẽ không được tuân theo.
Một spec thực dụng thường gồm: bảng token (spacing, type, radii, màu), một bộ quy tắc component ngắn (button, input, card, heading), quy tắc hành vi form (thời điểm validate, lỗi, disabled/loading), mặc định layout (padding trang, max width, khoảng cách section), và một danh sách “không bao giờ làm” ngắn (margin ngẫu nhiên, kích thước font ad-hoc).
Rồi tạo một thói quen: cập nhật spec trước, không sửa từng pixel.
Nếu bạn dùng Koder.ai (koder.ai), chế độ planning là nơi tốt để nhắc lại và xác nhận spec trước khi sinh UI. Khi muốn thử phương án khác, snapshots và rollback giúp bạn thử an toàn mà không mất baseline ổn định.
Bởi vì mỗi yêu cầu tạo màn hình là một khởi đầu mới. Nếu bạn không cung cấp một hệ thống chia sẻ, bộ sinh sẽ tự điền các chi tiết thiếu bằng cách phỏng đoán—spacing, kích thước chữ, padding nút, bóng, và hành vi form—vì vậy những khác biệt nhỏ tích tụ trên nhiều trang.
Design tokens là các giá trị có tên, có thể tái sử dụng cho những thứ như spacing, kích thước chữ, màu sắc và radius.
Thay vì nói “padding dễ chịu”, bạn dùng space-md. Tên token giữ ổn định và mỗi màn hình tái sử dụng cùng quyết định đó nên UI ngừng bị drift.
Bắt đầu nhỏ và chỉ bao phủ những thứ gây drift rõ rệt:
Nếu cần giá trị “mới”, làm tròn về token gần nhất thay vì tạo 10px hay 18px mới.
Đặt một khối UI spec ngắn ngay đầu mỗi yêu cầu và coi nó như một hợp đồng:
Rồi mô tả màn hình ở phía dưới. Chìa khóa là giữ spec không đổi giữa các màn hình.
Token xác định các con số; quy tắc component xác định thói quen. Một vài quy tắc hữu ích:
Quy tắc mặc định: nếu một variant không được chứng minh, quay về variant chuẩn.
Chọn một mẫu và dùng nó khắp nơi:
Điều này tránh tình trạng “màn hình này validate on blur, màn khác chỉ khi submit” khiến người dùng khó chịu.
Định nghĩa vài quy tắc trạng thái không thể thay đổi:
Nếu không chỉ định trạng thái, mỗi màn hình sẽ tự sáng tạo rồi lệch nhau.
Đừng để nó tự ứng biến kiểu dáng. Thêm nó như một mở rộng có tài liệu của một pattern hiện có:
Nếu bạn không thể mô tả bằng token, thường là quá tuỳ biến và sẽ gây drift.
Tạo một màn hình “tham chiếu” duy nhất (stress-test hệ thống) rồi dùng spec đó cho mọi màn hình mới.
Trong Koder.ai, bạn có thể dùng planning mode để nhắc lại và xác nhận spec trước khi tạo, và dùng snapshots và rollback để giữ baseline ổn định khi thử nghiệm.
Quét nhanh trước khi chấp nhận màn hình:
Nếu có gì sai, cập nhật spec/token rồi sinh lại—đừng vá margin một-off.