Morph Expand Card
點擊卡片以 shared layout 無縫形變放大為置中詳情面板,同組同時只展開一張。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
2
<MorphExpandCard />
安裝
npx shadcn@latest add https://webberui.com/r/morph-expand-card.json或在 components.json 設定 registries 後,改用 @webberui/morph-expand-card 安裝。
安裝依賴後,從 registry JSON(/r/morph-expand-card.json 的 files[0].content)複製 morph-expand-card.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion lucide-react clsx tailwind-merge使用
每張 MorphExpandCard 內放一個 MorphExpandCardSummary(收合內容)與一個 MorphExpandCardDetail(展開詳情)。外層以 MorphExpandGroup 包裹時,同組同時只會展開一張卡片。
import {
MorphExpandGroup,
MorphExpandCard,
MorphExpandCardSummary,
MorphExpandCardDetail,
} from "@/components/ui/morph-expand-card";
<MorphExpandGroup columns={2}>
<MorphExpandCard value="a" label="星雲濾鏡">
<MorphExpandCardSummary>
<div className="p-4 font-semibold">星雲濾鏡</div>
</MorphExpandCardSummary>
<MorphExpandCardDetail>
<div className="p-6">完整的詳情內容…</div>
</MorphExpandCardDetail>
</MorphExpandCard>
</MorphExpandGroup>;單張卡片也可獨立使用(不包 MorphExpandGroup),此時卡片自行管理開闔。
受控模式
在 MorphExpandGroup 傳入 value 與 onValueChange 即可外部控制目前展開的卡片:
const [open, setOpen] = React.useState<string | null>(null);
<MorphExpandGroup value={open} onValueChange={setOpen}>
{/* … */}
</MorphExpandGroup>;自訂關閉鈕
詳情面板預設在右上角提供關閉鈕。若要自訂位置,於 MorphExpandCardDetail 傳 hideDefaultClose,並在內容任意處放置 MorphExpandCardClose:
import { MorphExpandCardClose } from "@/components/ui/morph-expand-card";
<MorphExpandCardDetail hideDefaultClose>
<MorphExpandCardClose className="left-3" />
{/* … */}
</MorphExpandCardDetail>;Props
MorphExpandGroup
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
value | string | null | — | 受控模式:目前展開卡片的值(null 為全部收合) |
defaultValue | string | null | null | 非受控模式的初始展開值 |
onValueChange | (value: string | null) => void | — | 展開/收合變更時觸發 |
columns | number | 2 | 網格欄數(1–6) |
children | ReactNode | — | 放入 MorphExpandCard 子元件 |
MorphExpandCard
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
value | string | 自動產生 | 卡片唯一值,群組用它判斷展開對象 |
label | string | — | 無障礙標籤,套用於觸發卡片與詳情對話框 |
children | ReactNode | — | 需含一個 MorphExpandCardSummary 與一個 MorphExpandCardDetail |
MorphExpandCardDetail
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
hideDefaultClose | boolean | false | 隱藏預設右上角關閉鈕(改用自訂 MorphExpandCardClose) |
children | ReactNode | — | 展開時顯示的詳情內容 |
MorphExpandCardClose
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | ReactNode | X 圖示 | 自訂按鈕內容 |
細節
- 觸發卡片與詳情面板共用同一
layoutId,Motion 以 shared layout 讓卡片邊界框無縫形變為面板,收合時反向縮回原位。 - 詳情面板透過
createPortal掛載到document.body,並以固定定位置中,形變不受父層overflow或堆疊脈絡影響。 - 展開時原位卡片暫時
visibility: hidden,避免與形變中的面板重影。 - 展開會鎖住
body捲動,收合(或卸載)時還原;面板高度上限85vh,內容過長時內部捲動。
可及性
- 觸發卡片為
role="button"、可聚焦,支援 Enter/Space 展開;詳情面板為role="dialog"且aria-modal。 - 展開時焦點移入面板,收合後歸還觸發卡片;支援 Esc 收合、點擊遮罩收合。
- 傳入
label會同時作為卡片與對話框的aria-label。 - 使用者開啟「減少動態效果」時,形變位移歸零,改以短暫淡入淡出取代。