Caroa UI

Sheet

画面端からスライドインするシートコンポーネント。

インポート

import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter, SheetClose } from '@caroainc/ui-components/client'

個別サブパス(バンドルサイズを抑えたい場合):

import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter, SheetClose } from '@caroainc/ui-components/sheet'

Composition

Sheet
├─ SheetTrigger?
└─ SheetContent
   ├─ SheetHeader?
   │  ├─ SheetTitle
   │  └─ SheetDescription?
   ├─ 本文?
   └─ SheetFooter?
      └─ SheetClose?

SheetContentを表示する場合はSheetTitleが必須で、Trigger、本文、Footer、Closeは用途に応じて省略できます。SheetContentはPortalとOverlayを内部生成するため、Sheetの外へ出したり別のPortalで包んだりしないでください。

基本的な使い方

Loading...
<Sheet>
  <SheetTrigger asChild>
    <Button variant="outline">開く</Button>
  </SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>シートタイトル</SheetTitle>
      <SheetDescription>
        シートの説明文がここに入ります。
      </SheetDescription>
    </SheetHeader>
    <div className="py-4">
      メインコンテンツ
    </div>
    <SheetFooter>
      <SheetClose asChild>
        <Button>閉じる</Button>
      </SheetClose>
    </SheetFooter>
  </SheetContent>
</Sheet>

表示位置

Loading...
<SheetContent side="left">左から</SheetContent>
<SheetContent side="right">右から(デフォルト)</SheetContent>
<SheetContent side="top">上から</SheetContent>
<SheetContent side="bottom">下から</SheetContent>

ナビゲーション例

Loading...
<Sheet>
  <SheetTrigger asChild>
    <Button variant="outline">
      <Icon name="Menu" />
      メニュー
    </Button>
  </SheetTrigger>
  <SheetContent side="left" className="w-[300px]">
    <SheetHeader>
      <SheetTitle>ナビゲーション</SheetTitle>
    </SheetHeader>
    <nav className="flex flex-col gap-2 py-4">
      <Button variant="ghost" className="justify-start">
        <Icon name="Home" />
        ホーム
      </Button>
      <Button variant="ghost" className="justify-start">
        <Icon name="User" />
        プロフィール
      </Button>
    </nav>
  </SheetContent>
</Sheet>

閉じるボタンを非表示にする

showCloseButton={false} で右上の閉じるボタンを非表示にできます。フッターに独自の閉じるアクションを用意する場合などに使用します。

Loading...
<SheetContent showCloseButton={false}>
  <SheetHeader>
    <SheetTitle>閉じるボタンなし</SheetTitle>
  </SheetHeader>
  <SheetFooter>
    <SheetClose asChild>
      <Button>閉じる</Button>
    </SheetClose>
  </SheetFooter>
</SheetContent>

下へ引いて閉じる(スマホ向け)

side="bottom"にdraggableを付けると、上端につまみを出し、下へ引いて閉じられるようにします。上の角は丸めます。 つまみはマウスでも指でもどこから引いても動き、中身は指でスクロールが一番上のときに下へ引いたときだけ動きます (途中ではいつもどおりスクロールします)。離したとき、シートの高さの1/4(最大140px)より下げたか、速く下へ払ったら閉じ、 それ以外は元の位置へ戻ります。閉じるときはonOpenChange(false)を通ります。

Loading...
<SheetContent side="bottom" draggable className="max-h-[80dvh]">
  <SheetHeader>
    <SheetTitle>絞り込む</SheetTitle>
  </SheetHeader>
  <div className="overflow-y-auto px-4 py-4">中身</div>
</SheetContent>

Sheet以外の下からのパネル

地図の上のリストのように、Dialogにしない(背面を操作できる)下からのパネルにも、同じ動きとつまみを使えます。 useSheetDragはシートとつまみのrefを受け取り、引いている間のstyle(transform)を返します。閉じたらenabledを falseにします(位置が戻ります)。SheetHandleはシート自体がスクロールしても上端に留まり(sticky)、面の色と角の丸みは 親のシートから受け継ぎます。

import { SheetHandle, useSheetDrag } from '@caroainc/ui-components/sheet'

const sheetRef = React.useRef<HTMLElement>(null)
const handleRef = React.useRef<HTMLDivElement>(null)
const drag = useSheetDrag({ sheetRef, handleRef, enabled: open, onClose: () => setOpen(false) })

<section ref={sheetRef} style={drag.style} className="fixed inset-x-0 bottom-0 rounded-t-xl ...">
  <SheetHandle ref={handleRef}>
    {/* つまみの下に並べたものも、引くと動く帯になる(中のボタンは押せる) */}
  </SheetHandle>
  ...
</section>

Props (SheetContent)

PropTypeDefaultDescription
side'top' | 'right' | 'bottom' | 'left''right'シートの表示位置
showCloseButtonbooleantrue右上の閉じるボタンを表示するか
draggablebooleanfalseside="bottom"のとき、上端につまみを出し、下へ引いて閉じられるようにする
classNamestring-追加のCSSクラス