สอน HTML เบื้องต้น EP.3 - แบบฟอร์ม (Forms)

สรุปพื้นฐาน HTML Forms: โครงสร้าง form, action/method (GET/POST), ปุ่ม submit, การผูก label, ชนิด input, การตรวจสอบความถูกต้อง (Validation) และ Best Practices

Avatar Mac
10/08/2025

สำหรับคนที่มาอ่าน Blog นี้เป็น Blog แรก เราขอแนะนำให้อ่านบทความที่อยู่ในหัวข้อ อยากเป็น Frontend Developer ต้องรู้อะไรบ้าง? ก่อนนะครับเป็นหนึ่งใน Series Road to Frontend ที่จะช่วยให้คุณมีความรู้พื้นฐานที่จำเป็นสำหรับการเริ่มต้นเรียนรู้การพัฒนาเว็บไซต์

Meme Technology

Forms คืออะไร?

<form> คือ Tag HTML ที่ใช้สร้างฟอร์มสำหรับกรอกข้อมูล โดยไม่จำเป็นต้องใช้ JavaScript ก็สามารถส่งข้อมูลและตรวจสอบความถูกต้องเบื้องต้นได้

โครงสร้างพื้นฐานของฟอร์ม

<form action="/signup" method="POST">
  <label for="email">อีเมล</label>
  <input type="email" id="email" name="email" required>

  <label for="password">รหัสผ่าน</label>
  <input type="password" id="password" name="password" minlength="8" required>

  <button type="submit">สมัครสมาชิก</button>
</form>

action และ method ใน <form> คืออะไร?

  • action: URL ที่รับข้อมูลฟอร์ม ถ้าไม่ระบุจะส่งไปยัง URL ปัจจุบัน
  • method: โปรโตคอล HTTP ที่ใช้ส่งข้อมูล
    • GET: ส่งเป็น query string ต่อท้าย URL เหมาะกับการค้นหา/กรองข้อมูล (ไม่ควรส่งข้อมูลอ่อนไหว) เช่น https://example.com/search?email=dozildev@example.com&password=12345678
    • POST: ส่งใน request body เหมาะกับข้อมูลอ่อนไหว เช่น รหัสผ่าน บัตรเครดิต

ชื่อและค่าที่ถูกส่ง (name/value)

  • ข้อมูลที่ส่งให้ URL Action จะมีรูปแบบเป็น name=value โดยมาจาก attribute name ของ field ที่กรอกข้อมูล
<form method="GET">
  <label for="student">เลือกนักเรียน:</label>
  <select name="student" id="student">
    <option value="hoover">Hoover Sukhdeep</option>
    <option>Blendan Smooth</option>
    <option value="toasty">Toasty McToastface</option>
  </select>
  <input type="submit" value="ส่ง">
</form>

จากตัวอย่างข้างต้น จะส่งข้อมูลไปยัง URL ดังนี้ https://example.com/search?student=hoover

การใช้ <label> กับ <input>

  • ใช้ <label for="fieldId"> จับคู่กับ id ของ field เพื่อช่วยทั้ง UX และ Accessibility (หรือใช้ implicit label โดยครอบ input ไว้ภายใน <label>...</label>)
  • สามารถใช้แอตทริบิวต์ form บน field เพื่ออ้างถึง <form id="..."> ที่อยู่นอก DOM ต้นทางได้
<form id="reg"></form>

<!-- Field อยู่นอก <form> แต่ยังส่งไปกับฟอร์มผ่าน form="reg" -->
<label for="age">อายุ</label>
<input type="number" id="age" name="age" form="reg" min="0" step="1">

<button type="submit" form="reg">ส่ง</button>

Field ยอดนิยม

<!-- Text, Email, Password, Number -->
<input type="text" name="fullname" required>
<input type="email" name="email" autocomplete="email" required>
<input type="password" name="password" minlength="8" required>
<input type="number" name="quantity" min="1" max="10" step="1" value="1">

<!-- Radio (ให้อยู่กลุ่มเดียวกันด้วย name เดียวกัน) -->
<fieldset>
  <legend>เลือกขนาด</legend>
  <label><input type="radio" name="size" value="s" checked> S</label>
  <label><input type="radio" name="size" value="m"> M</label>
  <label><input type="radio" name="size" value="l"> L</label>
  <!-- การอยู่กลุ่มเดียวคือให้ค่า name เหมือนกัน ไม่ใช่ id -->
</fieldset>

<!-- Checkbox (ส่งได้หลายค่า ควรตั้งชื่อเป็น array เมื่อใช้กับ backend ที่รองรับ) -->
<fieldset>
  <legend>ท็อปปิ้ง</legend>
  <label><input type="checkbox" name="topping" value="cheese"> Cheese</label>
  <label><input type="checkbox" name="topping" value="bacon"> Bacon</label>
  <label><input type="checkbox" name="topping" value="mushroom"> Mushroom</label>
</fieldset>

<!-- Select / Textarea -->
<select name="country" required>
  <option>Thailand</option>
  <option>Japan</option>
  <option>USA</option>
  <!-- ไม่กำหนด value จะใช้ข้อความภายในเป็นค่า -->
</select>

<textarea name="bio" rows="4" maxlength="200" placeholder="แนะนำตัวสั้นๆ"></textarea>

การตรวจสอบความถูกต้อง (Constraint Validation) โดยไม่ใช้ JavaScript

เบราว์เซอร์ตรวจสอบค่าก่อนส่งฟอร์มอัตโนมัติเมื่อไม่มี novalidate บน <form> และไม่มี formnovalidate บนปุ่มที่กด

  • required, min, max, step, minlength, maxlength
  • ประเภทข้อมูล เช่น type="email", type="url" (มักต้องใช้ pattern เสริมเงื่อนไขให้เข้มขึ้น)
  • pattern สำหรับกำหนด regex ที่ค่าต้องแมตช์
<form action="/register" method="POST">
  <label for="mail">อีเมล</label>
  <input id="mail" name="mail" type="email" required pattern="^[^@\s]+@[^@\s]+\.[^@\s]+$">

  <label for="pwd">รหัสผ่าน (8–32 อักขระ)</label>
  <input id="pwd" name="pwd" type="password" minlength="8" maxlength="32" required>

  <button type="submit">ส่ง</button>
</form>

หากต้องการข้ามการตรวจสอบเพื่อเซฟแบบร่าง ให้ใส่ novalidate บน <form> หรือ formnovalidate บนปุ่มนั้น

<form action="/save" method="POST" novalidate>
  <!-- ฟอร์มนี้จะไม่ตรวจสอบค่า ก่อนส่ง -->
  <input name="title" required>
  <button type="submit">บันทึกแบบร่าง</button>
</form>

หมายเหตุ: สามารถใช้ JavaScript เรียก setCustomValidity('ข้อความแสดงข้อผิดพลาด') เพื่อกำหนดข้อความเองได้ และต้องล้างด้วยสตริงว่างเมื่อค่าถูกต้องเพื่อให้ส่งฟอร์มได้

Best Practices ที่ควรรู้

  • ใช้ <label> ผูกกับ field ทุกครั้ง เพื่อ A11y และพื้นที่คลิกที่ใหญ่ขึ้น
  • ใช้ autocomplete ให้เหมาะสม เช่น name, email, one-time-code เพื่อช่วยผู้ใช้กรอกเร็วขึ้น
  • เลือก method="POST" เมื่อมีข้อมูลอ่อนไหว และใช้ HTTPS เสมอ
  • อธิบายรูปแบบค่าที่คาดหวังเมื่อใช้ pattern และแจ้งข้อผิดพลาดอย่างชัดเจน
  • คำนึงถึงความหลากหลายทางวัฒนธรรม/รูปแบบข้อมูล (ชื่อ-ที่อยู่-รหัสไปรษณีย์ อาจต่างกันในแต่ละประเทศ)

แหล่งข้อมูลอ้างอิง: