HTMLボタン内にリンクを置くべきか?: <button> の中の <a> を考える
Web開発をしていると、見た目をボタンにしたリンクを作りたくなる場面があります。その際に「<button>
タグの中に<a>
タグを入れてもいいのか?」という疑問が生まれるかもしれません。
この記事では、<button>
タグの中に<a>
タグを使用する場合の問題点や、UIライブラリ shadcn/ui を使った解決策について解説します。
結論:避けるべき組み合わせ
<button>
の中に<a>
を置くことは 避けるべきです。以下の理由があります:
-
HTMLのセマンティクスの矛盾
-
<button>
は「ユーザーがアクションを起こすためのボタン」を表します。 -
<a>
は「他のページやリソースへのリンク」を表します。 - この2つを組み合わせると、ブラウザやユーザーに対してどの役割が優先されるべきか混乱を招きます。
-
-
アクセシビリティへの影響
- スクリーンリーダーを使用している場合、
<button>
と<a>
の意図を正しく伝えられない可能性があります。 - キーボード操作やフォーカス順序にも悪影響を及ぼすことがあります。
- スクリーンリーダーを使用している場合、
-
動作が不安定になるリスク
- ボタンをクリックしたときに、ブラウザがリンクとボタンのどちらを優先するか一貫性がありません。
- JavaScriptでのイベントハンドリングが複雑化する可能性があります。
shadcn/ui
を使った解決案:ボタンのスタイルを維持しつつリンクを実装する方法
HTMLのセマンティクスを壊さず、ボタンのスタイルを維持しつつリンクを実装する方法として、UIライブラリ shadcn/ui
を活用する方法があります。
shadcn/ui
では、asChild
や buttonVariants
を利用することで、見た目をボタン風に保ちながらリンクとしての機能を持たせることが可能です。
asChild
を使った実装
方法1: shadcn/ui
の Button
コンポーネントには、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>
);
}
buttonVariants
を使った実装
方法2: リンクにボタンのスタイルを直接適用する方法として、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 を活用すれば、asChild
や buttonVariants
により、リンクをボタンのように見せる実装が簡単になります。
Discussion