Bài 6. Xây dựng thành phần: nút, thẻ, form, navbar

Tailwind không có thành phần dựng sẵn như Bootstrap, nên bài này hướng dẫn tự xây bộ thành phần thường dùng: nút, badge, alert, thẻ, form đăng nhập, navbar có menu điện thoại, kèm cách tránh lặp lớp.

60 phútTrung cấp
Bạn sẽ học được
  • Xây nút theo biến thể và kích thước
  • Xây thẻ, alert, badge, avatar
  • Xây form đăng nhập có trạng thái
  • Xây navbar responsive có menu điện thoại

Một số khái niệm

Khi một tổ hợp lớp lặp lại nhiều lần, có 3 cách tránh lặp: (1) vòng lặp trong mã (PHP foreach, JS map); (2) thành phần của framework (React component, Blade component, PHP include); (3) cuối cùng mới dùng @utility hoặc @apply trong CSS (bài 9).

Nút và nhãn

<div class="flex flex-wrap items-center gap-2">
  <button class="rounded-lg bg-green-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600">Chính</button>
  <button class="rounded-lg bg-white px-4 py-2 text-sm font-semibold text-slate-900 ring-1 ring-slate-300 ring-inset hover:bg-slate-50">Phụ</button>
  <button class="rounded-lg px-4 py-2 text-sm font-semibold text-rose-600 hover:bg-rose-50">Xóa</button>
  <button class="rounded-full bg-sky-600 px-6 py-3 font-semibold text-white">Lớn</button>
  <button class="cursor-not-allowed rounded-lg bg-slate-200 px-4 py-2 text-sm text-slate-400" disabled>Vô hiệu</button>
  <span class="rounded-full bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-green-600/20 ring-inset">Hoàn thành</span>
</div>
<div class="mt-3 flex gap-3 rounded-lg border-l-4 border-amber-400 bg-amber-50 p-3 text-sm text-amber-800"><b>Lưu ý:</b> Hạn nộp bài còn 2 ngày.</div>
Kết quả hiển thị

Form đăng nhập

<form class="mx-auto max-w-sm space-y-4 rounded-2xl bg-white p-6 shadow-xl ring-1 ring-slate-200" onsubmit="return false">
  <h2 class="text-center text-xl font-bold text-slate-900">Đăng nhập</h2>
  <div><label class="mb-1 block text-sm font-medium text-slate-700" for="em">Email</label>
    <input id="em" type="email" required class="block w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:border-green-600 focus:ring-4 focus:ring-green-600/15 focus:outline-none" placeholder="Địa chỉ email này đang được bảo vệ từ spam bots, bạn cần kích hoạt Javascript để xem nó. Bạn cần kích hoạt Javascript để xem nó."></div>
  <div><div class="mb-1 flex justify-between text-sm"><label class="font-medium text-slate-700" for="mk">Mật khẩu</label><a href="#" class="text-green-700 hover:underline">Quên?</a></div>
    <input id="mk" type="password" class="block w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:border-green-600 focus:ring-4 focus:ring-green-600/15 focus:outline-none"></div>
  <label class="flex items-center gap-2 text-sm text-slate-600"><input type="checkbox" class="size-4 accent-green-600"> Ghi nhớ</label>
  <button class="w-full rounded-lg bg-green-600 py-2.5 font-semibold text-white hover:bg-green-500">Đăng nhập</button>
</form>
Kết quả hiển thị

Navbar có menu điện thoại

<nav class="rounded-xl bg-white shadow ring-1 ring-slate-200">
  <div class="flex items-center gap-6 px-4 py-3">
    <span class="font-extrabold text-green-700">Tự Học Tin</span>
    <div class="hidden gap-5 text-sm text-slate-600 sm:flex"><a class="hover:text-green-700" href="#">Khóa học</a><a class="hover:text-green-700" href="#">Lộ trình</a><a class="hover:text-green-700" href="#">Liên hệ</a></div>
    <button class="ml-auto rounded-lg p-2 hover:bg-slate-100 sm:hidden" onclick="document.getElementById('mm').classList.toggle('hidden')" aria-label="Mở menu">☰</button>
    <a href="#" class="ml-auto hidden rounded-lg bg-green-600 px-3 py-1.5 text-sm text-white sm:block">Đăng ký</a>
  </div>
  <div id="mm" class="hidden space-y-1 border-t px-4 py-2 text-sm sm:hidden"><a class="block rounded px-2 py-2 hover:bg-slate-100" href="#">Khóa học</a><a class="block rounded px-2 py-2 hover:bg-slate-100" href="#">Lộ trình</a><a class="block rounded px-2 py-2 hover:bg-slate-100" href="#">Liên hệ</a></div>
</nav>
Kết quả hiển thị

Khung hẹp nên hiện nút ☰; bấm để mở menu. Với dự án lớn, dùng thư viện như Headless UI, Alpine.js hoặc React để xử lý tương tác và trợ năng.

Mẹo hay

Tham khảo bố cục miễn phí trên Flowbite, HyperUI, DaisyUI (thư viện thành phần xây trên Tailwind) để học cách người khác ghép lớp.

Lưu ý

Khi tự làm menu, modal bằng JavaScript nhớ cập nhật thuộc tính aria-expanded, đóng bằng phím Esc và giữ focus hợp lý để người dùng bàn phím, trình đọc màn hình dùng được.

Thực hành
  1. Xây bộ nút 3 biến thể × 3 kích thước.
  2. Xây form đăng ký có hiển thị lỗi dưới ô.
  3. Xây navbar có menu điện thoại như ví dụ.
  4. Tách thẻ khóa học thành hàm JS hoặc tệp PHP include để dùng lại.
Tóm tắt bài học
  • Thành phần = tổ hợp lớp tiện ích.
  • Tránh lặp bằng vòng lặp, component, cuối cùng mới @apply.
  • ring, focus:ring, focus-visible: cho trạng thái.
  • hidden sm:flex, sm:hidden cho menu responsive.