Định dạng, trợ năng và xử lý dữ liệu form

Bài tổng kết về form: định dạng form đẹp và đồng nhất bằng CSS, bảo đảm người khuyết tật dùng được, đọc dữ liệu bằng JavaScript và xử lý ở máy chủ bằng PHP; cuối bài là dự án form đăng ký học phần hoàn chỉnh.

50 phútNâng cao
Bạn sẽ học được
  • Định dạng form gọn, đẹp, responsive
  • Áp dụng nguyên tắc trợ năng cho form
  • Đọc dữ liệu form bằng FormData, gửi bằng fetch
  • Nhận dữ liệu ở máy chủ bằng PHP và các dịch vụ không cần máy chủ
Thuật ngữ cần biết
Trợ năng (accessibility)
Khả năng người khuyết tật sử dụng được.
FormData
Đối tượng JavaScript chứa dữ liệu của form.
$_POST
Mảng PHP chứa dữ liệu gửi bằng POST.
CSRF
Tấn công giả mạo yêu cầu; cần token để chống.

Khái niệm và lý thuyết

Một form tốt: ngắn (chỉ hỏi điều cần), rõ ràng (nhãn ở trên ô, nhóm hợp lý), dễ bấm (ô cao tối thiểu 44px trên điện thoại), báo lỗi cụ thể và an toàn (HTTPS, kiểm tra ở máy chủ).

Định dạng form bằng CSS

<style>
  .f-dep { max-width: 420px; display: grid; gap: 12px; font-family: inherit; }
  .f-dep label { font-weight: 600; display: grid; gap: 4px; }
  .f-dep input, .f-dep select, .f-dep textarea {
    font: inherit; padding: 10px 12px; border: 1px solid #bdbdbd; border-radius: 8px; }
  .f-dep input:focus, .f-dep select:focus, .f-dep textarea:focus {
    outline: none; border-color: #2e7d32; box-shadow: 0 0 0 3px rgb(46 125 50 / .25); }
  .f-dep .hang { display: flex; gap: 12px; } .f-dep .hang label { flex: 1; }
  .f-dep { accent-color: #2e7d32; }
  .f-dep button { padding: 12px; border: 0; border-radius: 8px; background: #2e7d32; color: #fff; font-weight: 700; cursor: pointer; }
  .f-dep button:hover { background: #1b5e20; }
</style>
<form class="f-dep" onsubmit="alert('Đã gửi'); return false;">
  <div class="hang">
    <label>Họ <input name="ho" autocomplete="family-name" required></label>
    <label>Tên <input name="ten" autocomplete="given-name" required></label>
  </div>
  <label>Email <input type="email" name="email" autocomplete="email" required></label>
  <label>Học phần
    <select name="hoc_phan"><option>Thiết kế web</option><option>Lập trình Python</option></select>
  </label>
  <label style="font-weight:400; display:flex; gap:8px; align-items:center;"><input type="checkbox" required> Tôi đã đọc quy chế đào tạo</label>
  <button type="submit">Đăng ký học phần</button>
</form>
Kết quả hiển thị

accent-color đổi màu checkbox, radio, range theo màu thương hiệu chỉ với một dòng CSS.

Trợ năng cho form

  • Mọi ô đều có label; nhóm radio/checkbox đặt trong fieldset có legend.
  • Không chỉ dùng màu để báo lỗi: thêm chữ, biểu tượng.
  • Gắn thông báo hướng dẫn/lỗi bằng aria-describedby.
  • Thứ tự Tab hợp lý, có viền focus nhìn rõ; không xóa outline mà không thay thế.
  • Bắt buộc ghi rõ: dấu * kèm chú thích “(*) bắt buộc”.
<label for="cccd">Số CCCD *</label>
<input id="cccd" name="cccd" inputmode="numeric" pattern="[0-9]{12}" required aria-describedby="hd-cccd">
<small id="hd-cccd">Gồm 12 chữ số, in ở mặt trước thẻ.</small>

Đọc dữ liệu bằng JavaScript và gửi bằng fetch

<form id="f-js">
  <input name="ten" value="Lò Văn An"> <input name="lop" value="K66 Tin">
  <button>Xem dữ liệu</button>
</form>
<pre id="kq-js" style="background:#f5f5f5;padding:8px;"></pre>
<script>
  document.getElementById("f-js").addEventListener("submit", e => {
    e.preventDefault();
    const duLieu = Object.fromEntries(new FormData(e.target));
    document.getElementById("kq-js").textContent = JSON.stringify(duLieu, null, 2);
    // Gửi lên máy chủ: fetch("/api/dang-ky", { method: "POST", body: new FormData(e.target) })
  });
</script>
Kết quả hiển thị

Xử lý ở máy chủ bằng PHP

<?php
// dang-ky.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $hoTen = trim($_POST['ho_ten'] ?? '');
    $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
    if ($hoTen === '' || !$email) {
        exit('Dữ liệu không hợp lệ');
    }
    // Lưu CSDL bằng PDO với câu lệnh chuẩn bị (prepared statement)
    echo 'Xin chào ' . htmlspecialchars($hoTen) . '!';
}

Luôn kiểm tra lại dữ liệu, dùng htmlspecialchars khi hiển thị để chống XSS và prepared statement khi ghi CSDL để chống SQL injection. Không có máy chủ? Có thể gửi form tới Formspree, Google Apps Script hoặc dùng Google Forms.

Mẹo hay

Đặt nhãn phía trên ô nhập (thay vì bên trái) giúp form đọc nhanh hơn và tự nhiên trên điện thoại.

Lưu ý

Form có thao tác quan trọng (đổi mật khẩu, chuyển điểm) cần token chống CSRF và giới hạn số lần gửi để chống spam; các framework như Laravel, Django có sẵn cơ chế này.

Thực hành
  1. Hoàn thiện form đăng ký học phần ở trên, thêm ngày sinh, số điện thoại, ghi chú.
  2. Bổ sung thông báo lỗi dưới từng ô với aria-describedby.
  3. Hiển thị dữ liệu form dạng JSON bằng FormData.
  4. Viết dang-ky.php nhận và hiển thị dữ liệu, chạy thử trên XAMPP.
Tóm tắt bài học
  • Form tốt: ngắn, rõ, dễ bấm, báo lỗi cụ thể.
  • CSS grid, focus, accent-color giúp form đẹp và nhất quán.
  • Trợ năng: label, fieldset, aria-describedby, focus rõ.
  • FormData/fetch ở trình duyệt; máy chủ luôn kiểm tra và làm sạch dữ liệu.