shadcn/ui(Radix Primitives)のScrollAreaでmax-heightと可変の高さを設定する
この記事は株式会社ガラパゴス(有志)アドベントカレンダー2024の15日目の記事です。
日頃からお世話になっているshadcn/uiですが、時々痒いところに手が届かない場面があり、カスタマイズして利用しています。
今回は、Scroll Areaについて、max-height
を指定したい場面があったのでその実装方法を紹介します。shadcn/uiのScroll-areaはRadix PrimitivesのScroll Areaから作られています。
完成したUI
下記のUIでは以下を満たしています。
-
<ScrollArea />
にmax-height
を当てていて、固定のheight
は当てていない。 -
max-height
の値になるまでは、コンテンツによって高さが可変である。 -
max-height
を超えたらscroll可能になる。 - scroll可能になったら
<ScrollBar />
を表示する
<ScrollArea />
にmax-height
を有効にする
残念ながら、shadcn/uiのデフォルトの構成では<ScrollArea className="max-h-72" />
とするとスクロールができなくなります。
ただし、もともとのRadix Primitivesのissueを見ると、<ScrollArea.Viewport />
にmax-height
を指定するとスクロール可能になるそうで、実際にshadcn/uiの構成のViewportに指定したらスクロール可能になりました。
しかし、ScrollAreaを各所で実際に使用しており、<ScrollAreaPrimitive.Viewport />
を別コンポーネントとしてexport
したり、Viewport用のclassNameprops
やslot
分割はしたくない動機がありました。
そこで参考になったのが下記のissueコメントでした。
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
className={classX('flex flex-col relative overflow-hidden', className)}
>
<ScrollAreaPrimitive.Viewport
ref={ref}
className="flex-grow w-full rounded-[inherit]"
{...props}
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
このコメントでは以下の2つの変更により、
-
Root
にflex flex-col
を指定 -
Viewport
にflex-grow
を指定(h-full
から変更)
これにより、Root
明示的にheight
を渡さなくてもViewport
がRoot
に合わせた高さになってくれます。
デフォルトのViewport
がh-full
の場合、Root
のheight
を指定しないとViewport
がコンテンツの高さに合わせられてしまい、overflow-y: scroll;
が機能しなくなります。
これで、<ScrollArea className="max-h-72" />
に指定することで、max-height
以上になった時にscrollになることができました。
UXを改善する
このままでも実用可能なのですが、スクロール可否の状態を視覚的にユーザーに知らせたくなります。
Root
のAPIにtype
があります。デフォルは"hover"
になっており、hoverするまでスクロールの可否は分かりません。
Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars.
"auto"
means that scrollbars are visible when content is overflowing on the corresponding orientation.
"always"
means that scrollbars are always visible regardless of whether the content is overflowing.
"scroll"
means that scrollbars are visible when the user is scrolling along its corresponding orientation.
"hover"
when the user is scrolling along its corresponding orientation and when the user is hovering over the scroll area.MacOSのスクロールバー設定のように、スクロールバーの表示方法を制御するプロパティです。
"auto"
: コンテンツがはみ出している場合にのみスクロールバーを表示します
"always"
: コンテンツのはみ出しに関係なく、常にスクロールバーを表示します
"scroll"
: ユーザーがスクロールしている時のみスクロールバーを表示します
"hover"
: ユーザーがスクロールしている時、またはスクロールエリアにホバーした時にスクロールバーを表示します
これは単に<ScrollArea type="auto" className="max-h-72" />
とすることで解決できました。
結び
冒頭でshadcn/uiを"痒いところに手が届かない"と表現しましたが、むしろ利用者がカスタマイズできる柔軟性こそがshadcn/uiの素晴らしいコンセプトだと感じました。そして、Radix Primitives と Tailwind CSS にも感謝したい2024年冬。
Discussion