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

屬性名稱型別描述
childrenReact.ReactNode組件的子組件
classNamestring自定義 class
asReact.ElementType自定義 HTML tag

`Tabs`

屬性名稱型別描述
defaultValuestring預設 active 的 Tab
valuestring當前 active 的 Tab
onValueChange(value: string) => void當 Tab 改變時的 callback

`Tabs.List`

屬性名稱型別描述
loopboolean當在使用鍵盤作為導航時,是否循環

`Tabs.Trigger`

屬性名稱型別描述
disabledboolean是否禁用
valuestringTab 的值

`Tabs.Content`

屬性名稱型別描述
valuestringTab 的值

實作的重點整理:

在實作前,我們會用到先前介紹的幾個概念:

  1. Controlled & Uncontrolled State: 用來處理組件的狀態管理,可以讓使用者自行決定是否要控制組件的狀態,或是交由組件自行管理。
  2. Collection API: 用來處理組件的 index 問題的設計模式。
  3. 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>
  );
};

參考資料

  1. Radix UI - Tabs