Design System 101 - Tabs
- 文章發表於
什麼是 Tabs?
Tabs 是一種常見的組件,用來在同一畫面中將內容劃分為多個區塊,並可透過 Tab 來切換不同的內容。這種設計有助於整合並有效地展現分類資訊。
Tabs 的使用時機
何時使用
- 內容組織: 當有大量內容可以邏輯上分隔成不同類別時,使用 Tabs 有助於管理和呈現這些不同的資料集,而不會讓使用者感到信息過載。
- 任務分割: 如果內容包含多個相關的任務或動作,Tabs 可以讓使用者輕鬆在這些任務之間導航,而不需要離開當前的上下文。
何時不使用
- 分組過多: 如果我們有大量的分類或群組(例如,超過 6 個),使用 Tabs 可能不是最佳選擇,因為它們可能變得擁擠且難以閱覽。 - 使用 Drawer 組件可能更合適。
- 跨螢幕內容連結: 如果是需要在不同螢幕間連結內容,或是讓用戶同時看到多個 Tabs 的內容,Tabs 也不是最好的選擇。- 使用 Navigation Bar 組件可能更適合。
Anatomy
組件結構
組件 | 描述 |
---|---|
Tabs | 包含了所有 Tabs 組件,主要控制當前 active 的 Tab 狀態 |
Tabs.List | 包含所有 Tabs 的觸發控制 |
Tabs.Trigger | 用來觸發切換 Tabs 的事件 |
Tabs.Content | 用來顯示當前 active 的 Tab 內容 |
使用方式
<Tabs><Tabs.List><Tabs.Trigger>Tab 1</Tabs.Trigger><Tabs.Trigger>Tab 2</Tabs.Trigger></Tabs.List><Tabs.Content>Content 1</Tabs.Content><Tabs.Content>Content 2</Tabs.Content></Tabs>
組件 API
General Props
屬性名稱 | 型別 | 描述 |
---|---|---|
children | React.ReactNode | 組件的子組件 |
className | string | 自定義 class |
as | React.ElementType | 自定義 HTML tag |
`Tabs`
屬性名稱 | 型別 | 描述 |
---|---|---|
defaultValue | string | 預設 active 的 Tab |
value | string | 當前 active 的 Tab |
onValueChange | (value: string) => void | 當 Tab 改變時的 callback |
`Tabs.List`
屬性名稱 | 型別 | 描述 |
---|---|---|
loop | boolean | 當在使用鍵盤作為導航時,是否循環 |
`Tabs.Trigger`
屬性名稱 | 型別 | 描述 |
---|---|---|
disabled | boolean | 是否禁用 |
value | string | Tab 的值 |
`Tabs.Content`
屬性名稱 | 型別 | 描述 |
---|---|---|
value | string | Tab 的值 |
實作的重點整理:
在實作前,我們會用到先前介紹的幾個概念:
- Controlled & Uncontrolled State: 用來處理組件的狀態管理,可以讓使用者自行決定是否要控制組件的狀態,或是交由組件自行管理。
- Collection API: 用來處理組件的
index
問題的設計模式。 - Roving Focus: 用來處理鍵盤導航問題的設計模式,其適用於所有有群集的組件,例如:Tabs、Menu、Radio Group 等等。
了解上面這些概念之後,就可以很輕易的實作出一個 Tabs 組件了。
Tabs
: 主要是控制當前 active 的 Tab 狀態,並且提供onValueChange
callback 給使用者使用。Tabs.List
: 主要是用來包含所有的Tabs.Trigger
,並且將<RovingFocusGroup />
的邏輯套用在上面,讓鍵盤使用者可以透過鍵盤導航來切換 Tabs。Tabs.Trigger
: 主要是用來觸發切換 Tabs 的事件,以及使用useRovingFocus
hook 將本身的ref
加到 collection 中,這樣<RovingFocusGroup />
就可以知道當前有多少個可聚焦的組件,以便在鍵盤導航時可以正確的切換。Tabs.Content
: 根據value
顯示對應 Tab 的內容。
import React from 'react' import { Tabs } from './tabs.jsx' export default () => { return ( <Tabs defaultValue="tab1"> <Tabs.List loop> <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger> <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger> </Tabs.List> <Tabs.Content value="tab1">Content 1</Tabs.Content> <Tabs.Content value="tab2">Content 2</Tabs.Content> </Tabs> ) }
參考資料
如果您喜歡這篇文章,請點擊下方按鈕分享給更多人,這將是對筆者創作的最大支持和鼓勵。