🤖

HTMLボタン内にリンクを置くべきか?: <button> の中の <a> を考える

2024/12/13に公開

Web開発をしていると、見た目をボタンにしたリンクを作りたくなる場面があります。その際に「<button>タグの中に<a>タグを入れてもいいのか?」という疑問が生まれるかもしれません。

この記事では、<button>タグの中に<a>タグを使用する場合の問題点や、UIライブラリ shadcn/ui を使った解決策について解説します。


結論:避けるべき組み合わせ

<button>の中に<a>を置くことは 避けるべきです。以下の理由があります:

  1. HTMLのセマンティクスの矛盾

    • <button>は「ユーザーがアクションを起こすためのボタン」を表します。
    • <a>は「他のページやリソースへのリンク」を表します。
    • この2つを組み合わせると、ブラウザやユーザーに対してどの役割が優先されるべきか混乱を招きます。
  2. アクセシビリティへの影響

    • スクリーンリーダーを使用している場合、<button><a>の意図を正しく伝えられない可能性があります。
    • キーボード操作やフォーカス順序にも悪影響を及ぼすことがあります。
  3. 動作が不安定になるリスク

    • ボタンをクリックしたときに、ブラウザがリンクとボタンのどちらを優先するか一貫性がありません。
    • JavaScriptでのイベントハンドリングが複雑化する可能性があります。

shadcn/uiを使った解決案:ボタンのスタイルを維持しつつリンクを実装する方法

HTMLのセマンティクスを壊さず、ボタンのスタイルを維持しつつリンクを実装する方法として、UIライブラリ shadcn/ui を活用する方法があります。

shadcn/ui では、asChildbuttonVariants を利用することで、見た目をボタン風に保ちながらリンクとしての機能を持たせることが可能です。

方法1: asChild を使った実装

shadcn/uiButton コンポーネントには、asChild プロパティがあります。これを使うことで、Button 内部をカスタマイズ可能です。

以下の例では、Button コンポーネントに asChild を使い、内部に Link を配置してリンクボタンを実現しています。

import Link from "next/link";
import { Button } from "@/components/ui/button";

export default function Example() {
  return (
    <Button asChild>
      <Link href="/example">Go to Example</Link>
    </Button>
  );
}

方法2: buttonVariants を使った実装

リンクにボタンのスタイルを直接適用する方法として、buttonVariants を利用できます。

以下の例では、buttonVariants を使ってリンク要素をボタンのような見た目にしています。

import Link from "next/link";
import { buttonVariants } from "@/components/ui/button";

export default function Example() {
  return (
    <Link href="/example" className={buttonVariants({ variant: "outline" })}>
      Go to Example
    </Link>
  );
}

メリット

  • セマンティクスの維持: <a>タグをそのまま利用することで、HTMLの正しい構造を保ちながら、リンクとしての機能を実現します。
  • アクセシビリティ向上: ボタンの見た目を保ちながらリンクとして動作するため、スクリーンリーダーなどにも適切に対応します。

まとめ

<button><a> のセマンティクスを守ることは、アクセシビリティやコードの保守性にとって非常に重要です。

shadcn/ui を活用すれば、asChildbuttonVariants により、リンクをボタンのように見せる実装が簡単になります。

Discussion