2 คะแนน โดย GN⁺ 2026-01-21 | 4 ความคิดเห็น | แชร์ทาง WhatsApp
  • แม้ว่า ปุ่มตัวเลือก ที่มีมาในเว็บเบราว์เซอร์โดยพื้นฐานจะเป็นองค์ประกอบ HTML ที่เรียบง่าย แต่ในไลบรารี UI ของ Shadcn กลับถูกประกอบขึ้นใหม่เป็นคอมโพเนนต์ React หลายชั้น
  • <RadioGroup> และ <RadioGroupItem> ของ Shadcn ครอบคอมโพเนนต์จาก Radix UI อีกชั้นหนึ่ง และใช้ ไอคอนจาก lucide-react พร้อม คลาส Tailwind หลายสิบรายการ
  • Radix ใช้ แอตทริบิวต์ ARIA เพื่อการเข้าถึงและการปรับแต่ง แต่ในทางปฏิบัติกลับนำ element แบบปุ่มมาใช้ซ้ำแทน <input type="radio"> พื้นฐาน
  • ทั้งที่สามารถทำสไตล์แบบเดียวกันได้ด้วย CSS แบบเรียบง่าย โครงสร้างนี้กลับเพิ่ม โค้ดหลายร้อยบรรทัดและ dependency หลายตัว จนก่อให้เกิดความซับซ้อนที่ไม่จำเป็น
  • การไม่ใช้ element HTML พื้นฐานซ้ำทำให้ ประสิทธิภาพลดลงและภาระในการบำรุงรักษาเพิ่มขึ้น พร้อมทั้งบั่นทอนความเรียบง่ายของการพัฒนาเว็บ

วิเคราะห์โครงสร้างปุ่มตัวเลือกของ Shadcn

  • Shadcn ใช้คอมโพเนนต์สองตัวคือ <RadioGroup> และ <RadioGroupItem> เพื่อสร้างปุ่มตัวเลือก
    • แต่ละคอมโพเนนต์ครอบ primitive ที่นำเข้าจาก @radix-ui/react-radio-group และใช้ CircleIcon จาก lucide-react
    • มีโค้ดมากกว่า 45 บรรทัดและมี external import 3 รายการ พร้อมการกำหนดสไตล์ด้วย คลาส Tailwind มากกว่า 30 ตัว
  • มีโครงสร้างที่เรียกใช้ ไลบรารีไอคอน SVG เพียงเพื่อแสดงวงกลมแบบง่าย ๆ
    • ซึ่งเป็นสิ่งที่แทนได้ด้วย border-radius ของ CSS หรือ element <circle>

บทบาทของ Radix UI

  • Radix ที่ Shadcn ใช้งานคือ ไลบรารี UI คอมโพเนนต์ระดับล่างที่เน้นการเข้าถึงและการปรับแต่ง
    • การทำงานของ radio group ใน Radix ใช้ โค้ด React ราว 215 บรรทัด และ import ไฟล์ 7 ไฟล์
  • Radix เพิ่ม แอตทริบิวต์ ARIA ลงใน element <button> เพื่อให้ทำงานเหมือนปุ่มตัวเลือก
    • อย่างไรก็ตาม หลักการข้อแรกของการใช้ ARIA ของ W3C ระบุว่า “หากเป็นไปได้ให้ใช้องค์ประกอบ HTML พื้นฐาน”
    • แต่ Radix ไม่ได้ทำตามหลักนี้ และเลือกนำปุ่มมาใช้ซ้ำแทน <input>
  • ยังมีโครงสร้างที่เพิ่ม <input type="radio"> แบบซ่อนไว้เฉพาะภายใน <form> เท่านั้น ทำให้ขาดความสม่ำเสมอ

ทางเลือกที่เรียบง่ายด้วย CSS

  • ปุ่มตัวเลือก HTML พื้นฐานสามารถตกแต่งได้ง่ายด้วย appearance: none, ::before, :checked, border-radius เป็นต้น
    • ในโค้ดตัวอย่างสามารถปรับแต่งได้ครบถ้วนโดย ไม่ต้องพึ่ง dependency, JavaScript หรือแอตทริบิวต์ ARIA
    • เอฟเฟกต์แบบเดียวกันสามารถทำได้ด้วย Tailwind เช่นกัน
  • มุมมองที่ว่า “การตกแต่งปุ่มตัวเลือกเป็นเรื่องยาก” เป็นปัญหาจากอดีต และปัจจุบัน CSS ล้วนก็ให้การควบคุมได้เพียงพอ

ปัญหาของความซับซ้อนที่สะสม

  • เมื่อใช้ Shadcn ร่วมกับ Radix จำเป็นต้องทำความเข้าใจ ไลบรารีสองตัวและโค้ดหลายร้อยบรรทัด
    • เพียงเพื่อปุ่มตัวเลือกตัวเดียว กลับต้องโหลด JavaScript หลาย KB เพิ่มเติม
    • ผู้ใช้ต้องรอการ parse และรัน JS เพื่อให้การสลับปุ่มทำงาน
  • โครงสร้างเช่นนี้นำไปสู่ ภาระด้านการรับรู้ที่สูงขึ้น, โอกาสเกิดบั๊กที่มากขึ้น และ ประสิทธิภาพเว็บที่แย่ลง

การกลับไปหาความเรียบง่าย

  • เบราว์เซอร์มีปุ่มตัวเลือกให้ใช้อยู่แล้วโดยพื้นฐาน และเพียง <input type="radio" name="beverage" value="coffee" /> บรรทัดเดียวก็เพียงพอ
  • การทำ abstraction ที่ไม่จำเป็นและการใช้ไลบรารีซ้อนกันหลายชั้น เป็นการทำลาย ความเรียบง่ายและประสิทธิภาพดั้งเดิมของการพัฒนาเว็บ
  • แม้จะเป็นองค์ประกอบ UI ขนาดเล็ก การออกแบบที่ นำความสามารถพื้นฐานกลับมาใช้ซ้ำ ก็เป็นผลดีทั้งต่อการบำรุงรักษาและประสิทธิภาพ

4 ความคิดเห็น

 
crawler 2026-01-21

น่าเบื่อและแสร้งทำเป็นลึกซึ้ง:

function RadioGroup({  
  className,  
  ...props  
}: React.ComponentProps&lt;typeof RadioGroupPrimitive.Root&gt;) {  
  return (  
    &lt;RadioGroupPrimitive.Root  
      data-slot=&quot;radio-group&quot;  
      className={cn(&quot;grid gap-3&quot;, className)}  
      {...props}  
    /&gt;  
  );  
}  
...  

เสร็จเร็วแต่จำได้นาน:

&lt;input type=&quot;radio&quot; name=&quot;beverage&quot; value=&quot;coffee&quot; /&gt;  
 
slowandsnow 2026-01-22

ถ้าดูคอมโพเนนต์ปุ่มของ react aria คงเป็นลมไปเลย 555

 
preserde 2026-01-21

ผมอยู่สาย frontend เลยเจอปัญหานี้มานานมากแล้ว จะว่าไงดี มันก็เป็นปัญหาที่แก้ยากจริง ๆ ครับ แม้วิธี implement จะเปลี่ยนไปเรื่อย ๆ ตามยุคสมัย แต่สิ่งที่ไม่แก้ด้วย input type ก็ยังเหมือนเดิมทุกยุค... การพยายามเลียนแบบการทำงานของปุ่ม radio และ checkbox ในเว็บเบราว์เซอร์ แล้วไป implement สเปกด้าน accessibility แยกต่างหากนี่ สรุปคือจะทำไปเพื่ออะไรกันแน่... ไม่เข้าใจจริง ๆ... อย่างที่ในบทความบอก ตอนนี้ก็มีทางเลือกด้วย CSS แล้ว แต่พอเห็นว่ายังจะดันทุรังทำเป็นคอมโพเนนต์ให้ได้ ก็แอบขำเหมือนกันครับ

 
GN⁺ 2026-01-21
ความเห็นจาก Hacker News
  • ผมไม่ได้ทำฟรอนต์เอนด์บ่อยนัก แต่ตั้งแต่ช่วงที่ React กลายเป็นกระแสหลัก ก็เริ่มเห็นเค้าลางว่าความซับซ้อนจะเพิ่มขึ้น
    ชั้นของ abstraction อื่น ๆ มักมีแนวโน้มจะทำให้เรียบง่ายลง แต่ React กลับสร้าง abstraction ที่ซับซ้อนกว่า เทคโนโลยีพื้นฐานของมันมาก
    รู้สึกว่านักพัฒนาที่รู้แค่ React ค่อย ๆ สุมต่อขึ้นไปบนเลเยอร์ที่สูงกว่า จนได้ผลลัพธ์ที่ออกแบบเกินความจำเป็น

    • ตอนนี้ผมคิดว่าปัญหาหนักกว่าคือบรรยากาศที่ทุกคน มองว่า React เป็นค่าเริ่มต้นโดยอัตโนมัติ
      ตัวอย่างเช่น Shadcn หรือ Radix เป็นไลบรารี UI สำหรับ React โดยเฉพาะ แต่ถ้าดูแค่ข้อความการตลาดจะเหมือนเป็นไลบรารี UI ทั่วไป
    • ผมทำ UI ด้วย JavaScript และ DOM API แบบล้วน ๆ มามากกว่า 15 ปี
      พอขนาดงานใหญ่ขึ้น สุดท้ายก็มักต้องทำ framework ของตัวเองหรือไม่ก็ไม่พอใจกับ framework ที่มีอยู่ แต่ React ก็ช่วยแก้ปัญหานั้นได้ระดับหนึ่ง
      ผมมองว่าปัญหาไม่ใช่ React เอง แต่เป็น ความซับซ้อนส่วนเกินของ ecosystem ถ้าใช้ React เป็นก็ยังใช้งานได้อย่างเพลิดเพลิน
    • นี่ไม่ใช่ปัญหาเฉพาะของ React แต่ผมคิดว่าปัญหาใหญ่กว่าคือคนไม่ยอมเรียน CSS สมัยใหม่
      เอาแต่พยายามเลี่ยง CSS ด้วยเครื่องมืออย่าง Tailwind ผมใช้ React จัดการ state ก็จริง แต่เรื่อง styling ผมยังชอบเขียน CSS เองมากกว่า
      สิ่งที่ยากที่สุดคือการโน้มน้าวให้เพื่อนร่วมทีมยอมเรียน CSS
    • เดิมที abstraction ควรเป็น เครื่องมือเชิงปรัชญาที่ใช้ซ่อนความซับซ้อน แต่ทุกวันนี้กลับทำให้ซับซ้อนกว่าเดิมเสียบ่อย
      ผมจึงหลีกเลี่ยง framework ที่ “ทันสมัย” แบบนี้ และชอบ เทคโนโลยีพื้นฐาน ให้มากที่สุด
    • แก่นของ React คือ component abstraction
      React แค่ให้ “กล่อง” มา แล้วจะใส่อะไรไว้ข้างในเป็นสิ่งที่นักพัฒนาตัดสินใจเอง นั่นคือพลังที่แท้จริงของ React
  • ตัวอย่าง radio button นี้ทั้งน่าขำและน่าประทับใจ
    ผลลัพธ์แทบแยกไม่ออกจาก radio button CSS พื้นฐาน เลยสงสัยว่าทำไมต้องทำให้ซับซ้อนขนาดนี้
    อยากรู้ว่ามีเว็บขนาดใหญ่ที่สร้างขึ้นโดย ไม่มีความซับซ้อนเกินจำเป็น แบบนี้บ้างไหม

    • เว็บไซต์ McMaster-Carr มักถูกยกเป็นตัวอย่างที่ดี และมี เธรด Hacker News ที่เกี่ยวข้อง ด้วย
    • เมื่อ 15 ปีก่อนผมเคยทำเว็บแอปสำหรับงานวิดีโอร่วมกัน โดยฟรอนต์เอนด์แทบทั้งหมดเป็น โครงสร้างแบบ vanilla ที่ใช้ jQuery
      โค้ดเยอะกว่าตอนนี้ก็จริง แต่ตัวอินเทอร์เฟซมี ความไวในการตอบสนองทันที
      ดูได้จาก โค้ดของโปรเจกต์ Takeoff
    • “เว็บนี้ล่ะเป็นไง?” — บางที Hacker News เอง ก็อาจเป็นตัวอย่างแบบนั้น
    • ยิ่งบริษัทใหญ่ขึ้น ผู้จัดการก็มักต้องการ stack ที่เป็นมาตรฐาน
      มีคำพูดว่า “ไม่มีใครโดนไล่ออกเพราะเลือก React” มันเลยกลายเป็นตัวเลือกที่ปลอดภัย
    • UI เป็นสิ่งที่ทุกคนมองเห็นและมีความเห็นกันเยอะ จึงเป็นโครงสร้างที่ ความซับซ้อนขยายตัวแบบ tragedy of the commons
  • นักพัฒนาควรจำไว้ว่าสามารถ โต้แย้งข้อกำหนดด้านดีไซน์ได้เสมอ
    ตอนมีนักพัฒนาคนหนึ่งเสียเวลาไป 4 ชั่วโมงกับปัญหา layout ง่าย ๆ ใน React Native ผมบอกให้เขาลองถามว่า “เปลี่ยนดีไซน์นิดหน่อยได้ไหม” สุดท้ายแก้เสร็จใน 10 นาที

    • ช่วงนี้ผมชอบ UI framework ที่ไม่มี JS (Pico.CSS, Skeleton, Bulma, Tailwind/daisyUI)
      ถ้าใช้ CSS ให้ดีก็ได้ผลลัพธ์ที่ดีพอแล้ว อยากรู้ว่ามีใครใช้แนวทางนี้แล้วแนะนำอะไรบ้าง
  • ความผิดพลาดที่ใหญ่ที่สุดในปี 2025 คือการเลือก Shadcn
    ตอนเห็นว่าต้อง import Radix อยู่เรื่อย ๆ ก็เป็นสัญญาณเตือนครั้งแรก พอเห็นคอมโพเนนต์ radio ก็เป็นสัญญาณเตือนครั้งที่สอง
    แต่โปรเจกต์เดินไปแล้วเลยต้องยอมใช้ต่อและแก้ด้วย Copilot ซึ่งสุดท้ายก็ไม่ชอบ การพึ่ง AI แบบนั้นอยู่ดี
    POC ก่อนหน้านี้ทั้งง่ายและมีประสิทธิภาพกว่ามาก สักวันหนึ่งอยาก ทำใหม่ทั้งหมดด้วย vanilla HTML

    • ชุด React+NextJS+Tailwind+Shadcn คือ ที่สุดของความซับซ้อน
      อย่างน้อย Remix หรือ React Router 7 ก็ยังพยายามรักษาความใกล้กับมาตรฐานเว็บไว้
      ผมเริ่มรู้สึกว่า Tailwind “ไม่ใช่แล้ว” และถ้าเพื่อน ๆ ยังบอกว่ามันดีหลังรีแฟกเตอร์ค่อยกลับมาดูอีกที
    • จริง ๆ แล้ว Tailwind กับ React ไม่ค่อยเข้ากัน
      React มี การ styling แบบอิง props อยู่แล้ว เลยไม่มีเหตุผลมากนักที่จะไปใช้ก้อน CSS class ใหญ่ ๆ
      ถ้าเน้นเรื่อง accessibility ใช้แค่ Radix UI ก็น่าจะพอ
  • ปัญหาคือองค์ประกอบ <input> ของเบราว์เซอร์ โดยเฉพาะ radio และ select ปรับแต่งได้ยาก
    radio button แบบพื้นฐานก็ ใช้งานบนมือถือไม่ค่อยดี

    • จริง ๆ แล้ว native control ก็ styling ด้วย CSS ได้มากพอสมควร
      อยากรู้ให้ละเอียดกว่านี้ว่าบนมือถือมีปัญหาอะไร
    • ในบทความก็อธิบายวิธีตกแต่ง radio button ด้วย CSS อยู่แล้ว นั่นแหละคือปัญหาหรือ?
    • ถ้าห่อด้วย <label> แล้วใส่ padding ก็ใช้งานบนมือถือได้ดีพอแล้ว
    • มีแค่ “select” ที่ยัง styling ยากอยู่ แต่ที่เหลือปรับแต่งได้ค่อนข้างยืดหยุ่น
  • โปรเจกต์ส่วนใหญ่มักเริ่มต้นด้วยเจตนาดี แต่สุดท้ายก็เต็มไปด้วย โค้ด radio button ยาว 200 บรรทัด กับ import 7 ตัว
    นั่นแหละคือจุดเริ่มของ code rot

  • ไม่นานมานี้ผมลองใช้ daisyUI แล้วค่อนข้างชอบ
    มันอิง CSS ล้วน เลยใช้ ฟีเจอร์ใหม่ของเบราว์เซอร์ (เช่น dialog) ได้ดี

    • แต่ในด้าน accessibility ยังขาดอยู่อีกมาก
      ตัวอย่างเช่น Drawer กักโฟกัสไว้ไม่ได้ และ Accordion ก็ใช้ radio button แทน JS แบบเกินเลย
      ด้วยเหตุนี้ไลบรารีอย่าง Radix จึงหลีกเลี่ยงไม่ได้ที่จะซับซ้อน
  • ผมเห็นด้วยกับประเด็นหลักของบทความ แต่ก็สงสัยว่าถ้าต้อง ทำสไตล์จาก Figma ให้ตรงเป๊ะเหมือนกันทุกเบราว์เซอร์ จะทำได้ด้วย vanilla CSS จริงหรือ
    จะทำซ้ำของอย่าง เดโมของ Radix ได้ครบจริงไหม?

    • ปรับเล็กน้อยก็ทำให้คล้ายได้มากแล้ว
      ดู ตัวอย่าง CodePen ได้
    • สุดท้ายแล้ว ต่อให้มี framework ซับซ้อนอยู่ข้างใต้ CSS ก็ยังเป็นแกนหลัก
      แค่ดึง CSS ออกมาแล้วผูกกับคอมโพเนนต์ React แบบง่าย ๆ ก็น่าจะพอ
    • อย่าง ตัวอย่างนี้ ถ้าใช้ CSS เดียวกับ input แบบ vanilla ก็รองรับเบราว์เซอร์ได้ดี
    • ผู้เขียนบทความเองก็เข้ามาบอกว่า “ตัวอย่างพื้นฐานนี้แค่ปรับให้เข้ากับสไตล์ของ Shadcn เท่านั้น ถ้าต้องการก็ปรับแต่งได้มากเท่าที่อยากได้
    • แต่ก็ต้องคิดว่าจะไล่ตามความสมบูรณ์แบบไปถึงไหน
      แค่เพื่อหลีกเลี่ยงความไม่ตรงกันทางภาพเล็กน้อย จะคุ้มไหมถ้าต้องเพิ่ม โค้ดหลายสิบ KB และภาระการดูแลรักษา
      ก็ทำให้นึกถึงคำพูดของ Nam June Paik ว่า “ถ้าสมบูรณ์แบบเกินไป พระเจ้าจะโกรธ”
  • ต้นทุนที่แท้จริงไม่ใช่โค้ด แต่คือ เวลา onboarding
    ถ้านักพัฒนาคนใหม่จะต้องทำความเข้าใจ radio button 47 บรรทัดที่สร้างบน Radix อาจใช้เวลาหลายสัปดาห์
    แต่แบบ vanilla ใช้เวลาสร้างวันเดียว และอธิบายได้ใน 20 นาที
    แน่นอนว่าถ้าเป็นผลิตภัณฑ์อย่าง Figma หรือ Linear ที่ accessibility และ keyboard navigation สำคัญมาก ความซับซ้อนนั้นก็อาจสมเหตุสมผล

    • ก็น่าคิดว่าไลบรารีที่ดีไม่ควรต้องให้ผู้ใช้รู้โครงสร้างภายในก็ใช้งานได้หรือเปล่า
  • หลายคอมเมนต์วิจารณ์ Shadcn แต่ผมกลับมองว่ามันส่งเสริม โครงสร้างคอมโพเนนต์และการนำกลับมาใช้ซ้ำ ได้ดี
    แก่นของ Shadcn คือปรัชญา “ให้คุณเป็นเจ้าของคอมโพเนนต์และแก้ไขมันได้เอง”
    นี่เป็น แนวทางที่ต่างจาก UI library แบบเดิมอย่างพื้นฐาน