1. 06:27 06/08/2026
Khi phát triển web/app, nhiều đội thường tập trung vào màn hình “đẹp nhất”: có dữ liệu đầy đủ, thao tác chạy trơn tru, người dùng đi đúng luồng. Nhưng trong thực tế, người dùng gặp rất nhiều trạng thái khác: mạng chậm, danh sách rỗng, lỗi quyền truy cập, gửi form thành công nhưng chưa biết bước tiếp theo là gì. Nếu các trạng thái này bị làm qua loa, sản phẩm dễ tạo cảm giác thiếu tin cậy dù backend vẫn hoạt động tốt.
Một giao diện hoàn chỉnh nên được thiết kế như một tập hợp các trạng thái, không chỉ là một màn hình tĩnh.
Các trạng thái cơ bản nên có
1. Loading: đang tải dữ liệu
Loading không chỉ là spinner đặt giữa màn hình. Cần cân nhắc người dùng đang chờ gì và chờ trong bao lâu.
Ví dụ thực tế:
- Với bảng dữ liệu, có thể dùng skeleton row để người dùng biết cấu trúc nội dung sắp xuất hiện.
- Với nút gửi form, nên đổi nút thành “Đang lưu...” và vô hiệu hóa tạm thời để tránh bấm nhiều lần.
- Với thao tác ngắn, đôi khi chỉ cần loading nhỏ tại vùng liên quan, không cần khóa toàn bộ màn hình.
Lời khuyên: tránh dùng loading toàn trang cho mọi thứ. Nếu chỉ tải lại một khối nhỏ, hãy giữ phần còn lại của giao diện sử dụng được.
2. Empty state: không có dữ liệu
Danh sách rỗng không nên chỉ hiện “Không có dữ liệu”. Đây là cơ hội hướng dẫn người dùng làm bước tiếp theo.
Ví dụ:
- Trang quản lý dự án chưa có dự án nào: “Bạn chưa có dự án. Hãy tạo dự án đầu tiên để mời thành viên và theo dõi tiến độ.” kèm nút “Tạo dự án”.
- Kết quả tìm kiếm rỗng: “Không tìm thấy kết quả phù hợp. Thử bỏ bớt bộ lọc hoặc dùng từ khóa khác.”
Empty state tốt cần trả lời 3 câu hỏi: vì sao không có dữ liệu, người dùng có thể làm gì tiếp theo, có hành động chính nào cần nhấn không.
3. Error state: có lỗi xảy ra
Thông báo lỗi nên đủ rõ để người dùng biết cách xử lý, nhưng không lộ thông tin nhạy cảm như stack trace, câu SQL hay chi tiết hệ thống.
Ví dụ chưa tốt: “Error 500”.
Ví dụ tốt hơn: “Không thể tải danh sách đơn hàng. Vui lòng thử lại sau vài phút.” kèm nút “Thử lại”. Nếu lỗi liên quan đến quyền: “Bạn không có quyền xem nội dung này. Hãy liên hệ quản trị viên nếu cần truy cập.”
Với lập trình viên, nên tách thông điệp hiển thị cho người dùng và thông tin kỹ thuật trong log. Giao diện không cần nói hết lỗi nội bộ, nhưng hệ thống cần ghi đủ để debug.
4. Success state: thao tác thành công
Thành công cũng cần được thiết kế. Sau khi người dùng lưu, tạo, xóa hoặc gửi dữ liệu, họ cần biết thao tác đã hoàn tất và bước tiếp theo là gì.
Ví dụ:
- Sau khi tạo bài viết: chuyển đến trang chi tiết bài viết hoặc hiển thị “Đã tạo bài viết” kèm nút “Xem bài viết”.
- Sau khi lưu cài đặt: hiển thị toast ngắn “Đã lưu thay đổi”.
- Sau khi xóa dữ liệu: nếu phù hợp, cung cấp “Hoàn tác” trong vài giây.
Một số lỗi triển khai thường gặp
- Chỉ xử lý happy path, còn lỗi thì để console hoặc crash giao diện.
- Dùng chung một câu “Có lỗi xảy ra” cho mọi tình huống.
- Spinner quay vô hạn vì thiếu timeout hoặc thiếu nhánh xử lý khi API thất bại.
- Empty state không có hành động tiếp theo.
- Loading làm mất dữ liệu cũ ngay lập tức, khiến màn hình nhấp nháy khó chịu.
Gợi ý áp dụng trong dự án
Khi làm một màn hình mới, hãy liệt kê tối thiểu các trạng thái sau trước khi code UI:
- Lần đầu tải trang.
- Đang tải lại dữ liệu.
- Có dữ liệu.
- Không có dữ liệu.
- Lỗi tải dữ liệu.
- Đang gửi form.
- Gửi form thành công.
- Gửi form thất bại.
Nếu dùng frontend framework như React, Vue hoặc tương tự, nên quản lý trạng thái rõ ràng thay vì chỉ dùng một biến isLoading chung cho tất cả. Một màn hình có thể vừa có dữ liệu cũ, vừa đang tải dữ liệu mới, vừa có lỗi ở một thao tác phụ. Tách trạng thái đúng sẽ giúp UI chính xác hơn.
Kết luận
Thiết kế trạng thái giao diện không phải phần trang trí sau cùng, mà là một phần quan trọng của trải nghiệm sản phẩm. Loading rõ ràng giúp người dùng kiên nhẫn hơn, empty state tốt giúp họ biết bắt đầu từ đâu, error state tốt giúp giảm bối rối, còn success state tốt tạo cảm giác thao tác đáng tin cậy. Với web/app thực tế, chính những trạng thái “không hoàn hảo” này mới xuất hiện thường xuyên và quyết định người dùng có muốn tiếp tục sử dụng sản phẩm hay không.