【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 はコードを直接編集できるのが利点なので、以下の方法がおすすめです。
解決策1:button.tsx の基本スタイルを編集する (推奨✨)
これが一番直接的でクリーンな解決方法です。
-
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",
},
// ...
解決策2:!important で強制的に上書きする (最終手段 ⚠️)
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
同じ問題に直面しました。
バージョンが変わってからはcvaの中身が変わってるらしく、うまくやってくれるみたいです。
変更前:[&_svg]:size-4
変更後:[&_svg:not([class*='size-'])]:size-4