【Shadcn/ui】Button内のアイコンサイズが変更できない?原因は意外な基本スタイル!🛠️
はじめに
人気の UI コンポーネントライブラリ Shadcn/ui、便利ですよね! Button
コンポーネントもよく使うと思いますが、中に lucide-react
などのアイコンを入れたときに、「アイコンに className
でサイズ指定しても効かない!」と困ったことはありませんか?
import { Button } from "@/components/ui/button"; // あなたのプロジェクトの Button
import { Download } from "lucide-react";
// ...
<Button size="lg">
{/* h-10 w-10 (40px) にしたいのに、小さいまま… */}
<Download className="h-10 w-10" />
<span>ダウンロード</span>
</Button>
size="lg"
でボタン自体は大きくなるのに、なぜかアイコンだけ小さいまま...。デベロッパーツールで調べると、どうやら 1rem (16px)
くらいのサイズが強制されているみたい。
この謎、実はあなたのプロジェクト内にある button.tsx
ファイルに隠されています。この記事で、その原因を突き止め、具体的な解決策を見ていきましょう!
問題の状況:アイコンだけサイズが小さいまま
改めて状況を確認します。
- Shadcn/ui の
Button
コンポーネントを使用している。 - 中に
<Download />
などのアイコンコンポーネントを入れている。 - アイコンに
className="h-8 w-8"
やclassName="h-10 w-10"
を指定しても、表示されるアイコンのサイズが変わらない(多くの場合h-4 w-4
= 1rem/16px 相当のサイズになっている)。
button.tsx
の基本スタイル
コードの中に答えが!原因は Shadcn/ui の素晴らしい点の一つは、コンポーネントのコードが自分のプロジェクト内に直接コピーされることです。つまり、原因を突き止めて修正するのも簡単!
さっそく、あなたのプロジェクトの components/ui/button.tsx
ファイルを開いてみてください。
ファイルの中ほどに const buttonVariants = cva(...)
という記述があるはずです。cva
はクラス名を条件に応じて管理するライブラリですが、その最初の引数に注目してください。これは、ボタンのすべての種類(variant, size)に共通して適用される基本スタイルを定義する長い文字列です。
const buttonVariants = cva(
// ↓ この長い文字列が基本スタイル!
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
// ↑ この中に原因が! [&_svg]:size-4 がいる!
{
variants: {
variant: { /* ... */ },
size: { /* ... */ },
},
defaultVariants: { /* ... */ },
}
)
見つけましたか? 基本スタイルの文字列の最後の方に [&_svg]:size-4
というクラスがありますね!
[&_svg]:size-4
って何だっけ? (再確認)
これは Tailwind CSS の特殊な書き方(Arbitrary Variants)で、次のような意味でした。
-
[&_svg]
: 「この要素 (button
) の中にあるsvg
要素」というターゲット指定。 -
:size-4
: 見つけたsvg
要素にsize-4
(つまりwidth: 1rem; height: 1rem;
) を適用する。
つまり、Shadcn/ui の Button
は、デフォルトで、どんな variant
や size
であっても、中に入れた SVG アイコンのサイズを size-4
(1rem/16px) にしようとする 基本設定を持っているのです!
なぜアイコン自身のクラス指定が効かない?
これは CSS の優先順位(詳細度)の問題です。ボタンの基本スタイルとして定義された [&_svg]:size-4
から生成される CSS ルール(例: .buttonクラス名 svg { width: 1rem; height: 1rem; }
)が、あなたがアイコンに直接指定した .h-10
や .w-10
よりも優先されてしまうため、アイコン自身のクラス指定が上書きされて効かなくなっていたのです。
解決策! Shadcn/ui ボタンを使いこなす ✅
原因が button.tsx
の基本スタイルにあることが分かったので、解決策も明確です。Shadcn/ui はコードを直接編集できるのが利点なので、以下の方法がおすすめです。
button.tsx
の基本スタイルを編集する (推奨✨)
解決策1:これが一番直接的でクリーンな解決方法です。
-
components/ui/button.tsx
ファイルを開きます。 -
const buttonVariants = cva(...)
の最初の引数(基本スタイルの文字列) を見つけます。 - その文字列の中から
[&_svg]:size-4
の部分を削除します。
const buttonVariants = cva(
// ↓ 基本スタイルから [&_svg]:size-4 を削除!
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
// ↑ [&_svg]:size-4 を消した!
{
variants: { /* ... */ },
size: { /* ... */ },
defaultVariants: { /* ... */ },
}
)
これでどうなるか?
Button
コンポーネントは、デフォルトで内部のアイコンサイズを強制しなくなります。そのため、あなたがアイコンコンポーネント (<Download />
など) に直接指定した className="h-10 w-10"
のようなサイズ指定がそのまま有効になります!
応用編:
もし、「size="sm"
の時だけはアイコンを size-3
にしたい」のように、特定のボタンサイズやバリアントでのみデフォルトのアイコンサイズを設定したい場合は、基本スタイルから削除した後、variants
の中の該当する size
や variant
の定義文字列に [&_svg]:size-3
のようなクラスを追加することも可能です。
// ...
size: {
default: "h-10 px-4 py-2 [&_svg]:size-4", // default では size-4 を維持
sm: "h-9 rounded-md px-3 [&_svg]:size-3", // sm では size-3 にする
lg: "h-11 rounded-md px-8", // lg では指定しない (アイコン自身のクラスに従う)
icon: "h-10 w-10",
},
// ...
!important
で強制的に上書きする (最終手段 ⚠️)
解決策2:button.tsx
を編集したくない、あるいは一時的に特定の箇所だけ上書きしたい場合の最終手段です。アイコンに指定するクラス名の先頭に !
を付けます。
<Button size="lg">
<Download className="!h-10 !w-10" /> {/* ← ! を付けて強制上書き */}
<span>ダウンロード</span>
</Button>
これは button.tsx
の指定よりも優先されますが、!important
はスタイルの管理を複雑にする可能性があるため、Shadcn/ui のようにコンポーネントコードを直接編集できる場合は、解決策1(button.tsx
の編集)の方が推奨されます。
まとめ
Shadcn/ui の Button
コンポーネントでアイコンサイズが固定されてしまう原因は、components/ui/button.tsx
内の cva
定義にある基本スタイル [&_svg]:size-4
でした。
一番のおすすめ解決策は、button.tsx
ファイルを開き、基本スタイルから [&_svg]:size-4
を削除することです。これにより、アイコンに直接指定した Tailwind のサイズクラスが有効になります。
Shadcn/ui はコードを自由にカスタマイズできるのが魅力です。内部の仕組みを少し理解するだけで、より柔軟にコンポーネントを使いこなせるようになりますね!
Discussion