Alphabet Ledger
字母索引卷軸:海報級巨型首字母作為每個區段的 sticky 錨點,交接時新字母把前一個推出並做字重由細到粗的交棒動畫。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
200
800
<AlphabetLedger />
安裝
npx shadcn@latest add https://webberui.com/r/alphabet-ledger.json或在 components.json 設定 registries 後,改用 @webberui/alphabet-ledger 安裝。
安裝依賴後,從 registry JSON(/r/alphabet-ledger.json 的 files[0].content)複製 alphabet-ledger.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
import {
AlphabetLedger,
AlphabetLedgerSection,
} from "@/components/ui/alphabet-ledger";
<AlphabetLedger>
<AlphabetLedgerSection letter="A" label="Animation">
<p>內容會在巨型字母旁捲動……</p>
</AlphabetLedgerSection>
<AlphabetLedgerSection letter="B" label="Baton">
<p>捲到這裡時,B 會把 A 推出並補上粗字重。</p>
</AlphabetLedgerSection>
</AlphabetLedger>若捲動發生在巢狀 overflow-y-auto 容器內,將該容器的 ref 傳給 container:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[320px] overflow-y-auto">
<AlphabetLedger container={scrollerRef}>{/* ... */}</AlphabetLedger>
</div>Props
AlphabetLedger
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | ReactNode | — | 放入 AlphabetLedgerSection,每個為一個字母區段 |
showIndex | boolean | true | 是否顯示右側可點擊的字母索引卷軸 |
thinWeight | number | 200 | 非活躍字母的字重(細) |
boldWeight | number | 800 | 活躍字母的字重(粗),交棒瞬間補到此值 |
letterSizeClassName | string | "text-[5.5rem] leading-none sm:text-[8rem]" | 巨型字母的字型級距類名 |
letterClassName | string | — | 覆寫巨型字母樣式(顏色、字距等) |
container | RefObject<HTMLElement | null> | — | 巢狀捲動容器 ref,作為釘住偵測與捲動目標 |
onActiveChange | (index: number, letter: string) => void | — | 活躍區段變動時回呼 |
className | string | — | 附加在外層容器 |
AlphabetLedgerSection
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
letter | string | — | 作為區段錨點的巨型首字母 |
children | ReactNode | — | 區段內容,會在字母旁捲動 |
label | ReactNode | — | 字母下方小標,字串型別時同時作為區段的可及性名稱 |
id | string | — | 套用在區段上的錨點 id |
className | string | — | 附加在區段容器 |
運作細節
- 每個區段的巨型首字母以
position: sticky; top: 0釘在頂端,字母的移動被自己的區段邊界所限;當區段捲到底,下一個區段的字母隨即釘住,視覺上把前一個「推出」。 - 交接瞬間,接手字母的
fontWeight由thinWeight補到boldWeight(配合微幅縮放),前一個同時退回細字重,形成「交棒」動畫。字重過渡的平滑度取決於字型是否為可變字重字型(variable font)。 - 活躍區段由
IntersectionObserver判定:以最深層已越過頂端釘住線的區段為活躍者,右側索引卷軸與字重同步更新。 - 傳入
container時,釘住偵測(IntersectionObserverroot)與索引卷軸的捲動定位都會改用該容器;不傳則以視窗為捲動容器。
可及性
- 巨型字母為裝飾性視覺錨點,標記
aria-hidden;請在區段內容中提供實際標題,label為字串時會作為<section>的aria-label。 - 右側索引卷軸為原生
<button>,可鍵盤聚焦、Enter 觸發,並帶有aria-label與aria-current標記當前區段。 - 使用者系統開啟「減少動態效果」時,sticky 堆疊版面完整保留,僅停用字重交棒過渡與平滑捲動(改為即時跳位)。