2 ポイント 投稿者 GN⁺ 2026-01-21 | 4件のコメント | WhatsAppで共有
  • Webブラウザに標準搭載されているラジオボタンは単純なHTML要素であるにもかかわらず、Shadcn UIライブラリではこれを複数階層のReactコンポーネントとして再構成している
  • Shadcnの<RadioGroup><RadioGroupItem>Radix UIのコンポーネントをさらにラップし、lucide-reactアイコン数十個のTailwindクラスを使用している
  • Radixはアクセシビリティとカスタマイズ性のためにARIA属性を活用しているが、実際には基本の<input type="radio">ではなくボタン要素を再利用している
  • 単純なCSSだけでも同じスタイリングが可能であるにもかかわらず、この構造は数百行のコードと複数の依存関係を追加し、不必要な複雑さを招いている
  • 基本のHTML要素を再利用しないことで性能低下と保守負担が大きくなり、Web開発の単純さが損なわれる

Shadcnのラジオボタン構造の分析

  • Shadcnは<RadioGroup><RadioGroupItem>の2つのコンポーネントを通じてラジオボタンを実装している
    • 各コンポーネントは@radix-ui/react-radio-groupから取り込んだプリミティブをラップし、lucide-reactCircleIconを使用している
    • 45行を超えるコードと3つの外部importを含み、30個を超えるTailwindクラスでスタイル指定している
  • 単純な円形表示のためにSVGアイコンライブラリを読み込む構造
    • CSSのborder-radius<circle>要素で代替できる機能である

Radix UIの役割

  • Shadcnが使用するRadixはアクセシビリティとカスタマイズ性を重視した低レベルUIコンポーネントライブラリ
    • Radixのラジオグループ実装は約215行のReactコードと7個のファイルをimportする
  • Radixは<button>要素にARIA属性を追加してラジオボタンのように動作するよう構成している
    • しかし、W3CのARIA利用の第1原則では「可能な場合は標準のHTML要素を使うこと」と明記している
    • Radixはこの原則に従わず、<input>の代わりにボタンを再利用している
  • <form>内部でのみ隠された<input type="radio">を追加する構造になっており、一貫性に欠ける

CSSで可能な単純な代替案

  • 標準のHTMLラジオボタンはappearance: none::before:checkedborder-radiusなどで容易にスタイリングできる
    • 例示コードでは依存関係、JavaScript、ARIA属性なしで完全なカスタマイズを実現している
    • 同じ効果はTailwindでも実装可能である
  • 「ラジオボタンのスタイリングは難しい」という認識は過去の問題であり、現在では純粋なCSSだけで十分に制御可能

複雑さの蓄積という問題

  • ShadcnとRadixを併用すると2つのライブラリと数百行のコードを理解しなければならない
    • 単純なラジオボタン1つのために数KBのJavaScriptが追加で読み込まれる
    • ユーザーはボタンの切り替えのためにJSの解析と実行を待たなければならない
  • このような構造は認知負荷の増加バグの可能性拡大Web性能の低下につながる

単純さへの回帰

  • ブラウザはすでにラジオボタンを標準提供しており、<input type="radio" name="beverage" value="coffee" />の1行で十分
  • 不必要な抽象化や入れ子になったライブラリの使用はWeb開発本来の単純さと効率を損なう
  • 小さなUI要素であっても基本機能を再利用する設計が保守性と性能の両方に有利である

4件のコメント

 
crawler 2026-01-21

退屈で衒学的:

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

すぐ終わるし、長く記憶に残る:

<input type="radio" name="beverage" value="coffee" />  
 
slowandsnow 2026-01-22

react aria のボタンコンポーネントを見たら気絶しそうww

 
preserde 2026-01-21

私がフロントエンド分野だから長い間経験してきた問題なのですが、何というか本当に解決が難しい問題ではあります。実装は時代によってずっと変わっていますが、input typeで解決しないのはどの時代でも同じですね...
Webブラウザのラジオボタンやチェックボックスの動作をまねようとして、アクセシビリティ関連の仕様を別途実装するのはいったい何のためなのか... よく分かりません... 本文にあるようにCSSでも今は代案があるのに、どうしてもコンポーネントとして実装しようとするのを見ると、ちょっと笑ってしまいます。

 
GN⁺ 2026-01-21
Hacker Newsの意見
  • フロントエンドを頻繁に扱うわけではないが、Reactが主流になり始めた時点から複雑性が増す兆候は見えていた
    他の抽象化レイヤーは単純化する傾向があるのに、Reactはその基盤技術よりはるかに複雑な抽象化を生み出している
    Reactしか知らない開発者たちがますます高いレイヤーへ積み上げていき、過剰設計の結果を生んでいるように感じる

    • 今では、誰もがReactをデフォルトだと当然視している空気のほうが問題だと思う
      たとえば ShadcnRadix はReact専用UIライブラリなのに、マーケティング文句だけ見ると一般的なUIライブラリのように見える
    • 私は15年以上、純粋なJavaScriptとDOM APIでUIを作ってきた
      規模が大きくなると結局は自分専用のフレームワークを作るか、既存フレームワークに不満を抱くことになったが、Reactはその問題をある程度解決してくれる
      React自体よりもエコシステムの過剰な複雑性が問題だと見ている。Reactさえうまく扱えれば、今でも楽しく使える
    • これはReactだけの問題ではなく、人々がモダンCSSを学ぼうとしないことのほうが大きな問題だと思う
      TailwindのようなツールでCSSを回避しようとしているだけだ。私はReactで状態管理はするが、スタイリングはCSSで直接やるほうを好む
      チームメンバーにCSSを学ばせるよう説得するのがいちばん難しい
    • 抽象化は本来、複雑性を隠す哲学的ツールであるべきなのに、最近はむしろさらに複雑にしてしまう場合が多い
      私はこうした「モダンな」フレームワークを避け、できるだけ基本技術を好む
    • Reactの核心はコンポーネント抽象化にある
      Reactは単に「箱」を提供し、その中に何を入れるかは開発者が決める。それがReactの本当の力だ
  • このラジオボタンの例は笑えると同時に印象的だ
    出来上がったものは標準CSSのラジオボタンと見分けがつかないのに、なぜここまで複雑にするのか疑問だ
    大規模サイトの中で、こうした不要な複雑性なしに作られた事例があるのか気になる

    • McMaster-Carr のサイトが良い例としてよく挙げられる。関連する Hacker Newsスレッド もある
    • 15年前に動画コラボレーションWebアプリを作ったが、フロントエンドはほぼjQueryベースのバニラ構成だった
      今よりコード量は多かったが、インターフェースには即応性のあるスピード感があった
      Takeoffプロジェクトのコード を参照できる
    • 「このサイトはどう?」— まさにこのHacker News自体がその一例かもしれない
    • 会社の規模が大きくなるほど、管理者は標準化されたスタックを求める
      「Reactを選んでクビになった人はいない」という言葉のように、安全な選択になってしまっている
    • UIは誰もが見えて意見を言いやすいので、複雑性が共有地の悲劇のように膨らむ構造になっている
  • 開発者は、デザイン要件にいつでも異議を唱えられることを覚えておくべきだ
    React Nativeで単純なレイアウト問題に4時間を無駄にしていた開発者に「デザインを少し変えてもいいか聞いてみたら?」と言ったところ、10分で解決した

    • 私は最近、JSなしのUIフレームワーク(Pico.CSS、Skeleton、Bulma、Tailwind/daisyUI)を好んでいる
      CSSさえしっかり書ければ十分に良い結果が得られる。こういうアプローチを使った人のおすすめがあれば知りたい
  • 2025年最大の失敗はShadcnを選んだことだった
    Radixを延々とimportしているのを見て最初の警告を感じ、radioコンポーネントを見て二度目の警告を感じた
    すでにプロジェクトが進んでいたので諦めてCopilotで修正したが、結果としてAI依存になったことも気に入らなかった
    以前のPOCのほうがずっと単純で効率的だった。いつか全部バニラHTMLで作り直したい

    • React+NextJS+Tailwind+Shadcnの組み合わせは複雑さの極み
      RemixやReact Router 7はそれでもWeb標準に近づけようとする試みがあった
      Tailwindの時点で「これは違う」と感じたので、友人たちがリファクタリング後も良いと言うならそのとき見直すつもりだ
    • 実際、TailwindとReactは相性が良くない
      Reactにはpropsベースのスタイリングがあるのに、わざわざCSSクラスの塊を使う理由がない
      アクセシビリティ重視ならRadix UIだけで十分だ
  • ブラウザの<input>要素、とくにradioとselectはカスタマイズしにくいのが問題だ
    標準のラジオボタンはモバイルで使い勝手が悪い

    • 実際にはネイティブコントロールもCSSで十分スタイル調整できる
      モバイルでどんな問題があったのか、もっと具体的に知りたい
    • 記事でもCSSでラジオボタンを装飾する方法を説明している。それが問題なのだろうか?
    • <label>で包んでパディングを与えれば、モバイルでも十分実用的だ
    • “select”だけはいまだにスタイリングが厄介だが、それ以外はかなり柔軟にカスタマイズできる
  • ほとんどのプロジェクトは善意で始まるが、気づけば200行のラジオボタンコードと7つのimportで埋め尽くされる
    こうしてコードの腐敗(code rot) が始まる

  • 最近 daisyUI を使ってみたが、かなり気に入った
    純粋なCSSベースなので、ブラウザの**新しい機能(dialogなど)**をうまく活用できる

    • ただしアクセシビリティの面では不足が多い
      たとえば Drawer はフォーカスを閉じ込められず、Accordion はラジオボタンをJS代替として乱用している
      こうした理由でRadixのようなライブラリは複雑にならざるを得ない
  • 記事の趣旨には共感するが、デザイナーがFigmaで作った正確なスタイルをすべてのブラウザで同一に実装するには、バニラCSSで可能なのか気になる
    Radixのデモ のようなものを完全に再現できるだろうか?

    • 少し手を加えるだけでもかなり近いものは作れる
      CodePenの例 を参照できる
    • 結局、あの複雑なフレームワークの下でもCSSが核心
      CSSだけ抜き出してシンプルなReactコンポーネントに貼れば十分だ
    • この例 のようにバニラinputと同じCSSを適用すれば、ブラウザ互換性も良い
    • 記事の筆者本人が登場して、「基本例を単にShadcn風のスタイルに合わせただけで、望めばいくらでもカスタマイズ可能だ」と明かしている
    • ただ、どこまで完璧さを追求するのかは悩ましい
      わずかな見た目の不一致を避けるために数十KBのコードと保守負担を追加することに、本当に価値があるのだろうか?
      ナム・ジュン・パイクの言葉のように「完璧すぎると神が怒る」と感じる
  • 本当のコストはコードではなくオンボーディング時間
    新しく参加した開発者がRadixベースの47行のラジオボタンを理解するのに数週間かかる
    一方、バニラ方式なら1日で作れ、20分で説明できる
    もちろんFigmaやLinearのようにアクセシビリティとキーボードナビゲーションが重要な製品なら、その複雑性は正当化される

    • 良いライブラリは内部構造を知らなくても使えるようにすべきではないか、という疑問がある
  • 多くのコメントはShadcnを批判しているが、私はむしろコンポーネント構造と再利用性をうまく促進していると思う
    Shadcnの核心は「コンポーネントを自分で所有し、自分で修正せよ」という哲学だ
    これは既存のUIライブラリとは根本的に異なるアプローチ