徵求開發人員意見回饋:focusgroup

Jacques Newman
Jacques Newman

發布日期:2026 年 3 月 5 日

focusgroup HTML 屬性是建議的宣告方式,可將鍵盤方向鍵導覽功能新增至工具列、分頁清單、選單、清單方塊等複合式小工具,無須編寫任何 roving-tabindex JavaScript。一個屬性取代數百行的樣板。請在正式推出前提供意見回饋。

歡迎試用並提供意見

您可以在 Chrome、Edge 和其他 Chromium 瀏覽器中試用 focusgroup,方法如下:

  1. 在本機測試:在瀏覽器中開啟 about://flags 頁面,然後啟用「Experimental Web Platform features」(實驗性網頁平台功能) 旗標。或者,使用 --enable-blink-features=Focusgroup 指令列參數,從指令列啟動瀏覽器。
  2. 原始碼試用:註冊參加焦點團體原始碼試用,在網站上與實際使用者一起測試。

接著,請探索互動式範例,查看每個模式的實際運作情形。

我們需要您的意見回饋。提出焦點團體問題,與我們分享您的想法。

這項提案是 跨瀏覽器合作的成果,由 Microsoft 透過 OpenUI 社群群組提出,並獲得 Google 的大力支持。API 形狀可能會根據您的意見回饋而有所變更。 讓我們深入瞭解 focusgroup 解決的問題,以及 API 的運作方式。

問題:手動漫遊 tabindex

如果您曾建構工具列、分頁清單、選單或清單方塊,就曾編寫過某個版本的這段程式碼。ARIA 撰寫實務指南 (APG) 建議複合式小工具提供單一 Tab 鍵停駐點,並讓使用者透過方向鍵在項目間移動。這種模式稱為「漫遊 tabindex」。許多 UI 架構都會從頭重新實作這項功能:

<div role="toolbar" aria-label="Text formatting" id="toolbar">
  <button type="button" tabindex="0">Bold</button>
  <button type="button" tabindex="-1">Italic</button>
  <button type="button" tabindex="-1">Underline</button>
  <button type="button" tabindex="-1">Strikethrough</button>
</div>

接著,開發人員必須使用 JavaScript 監聽方向鍵,藉此移動焦點,並調整所有元素的 tabindex 屬性。這是簡化版本。正式版實作項目也必須處理下列事項:

  • 書寫模式和從右到左 (RTL):根據內容方向調整方向鍵方向。
  • 上次聚焦的記憶體:使用者返回時,將焦點還原至先前啟用的項目。
  • 已停用及隱藏的項目:在導覽期間略過這些項目。
  • 動態項目:新增或移除項目時,請更新漫遊索引。

大多數 UI 程式庫 (包括 ReactAngular CDKFluent UI) 都會提供這個邏輯的專屬版本。這會導致許多重複作業,但其實可以透過平台基本型別達成。

解決方案:focusgroup 屬性

使用 focusgroup 時,相同的工具列會變成:

<div focusgroup="toolbar" aria-label="Text formatting">
  <button type="button">Bold</button>
  <button type="button">Italic</button>
  <button type="button">Underline</button>
  <button type="button">Strikethrough</button>
</div>
功能表列,焦點位於斜體按鈕。

立即試用: 工具列模式 > 基本工具列。 就是這麼簡單!沒有用於方向鍵瀏覽的 JavaScript。不需要手動管理 tabindex。瀏覽器現在會為您處理下列事項:

  • 方向鍵導覽:在項目之間移動,同時遵守書寫模式和方向性。
  • 單一 Tab 鍵停駐點:瀏覽器會自動將參與項目摺疊成一個 Tab 鍵停駐點。開發人員不需要在非使用中項目上設定 tabindex="-1"
  • 記憶上次焦點:使用者離開焦點群組並返回時,焦點會還原至離開時的項目。
  • ARIA 語意:使用一般元素時,瀏覽器會根據所選行為提供適當的角色 (例如 role="toolbar")。

開發人員只會保留功能專屬的邏輯,例如切換按下狀態、開啟選單、管理選取項目或任何自訂指令。

API 總覽

focusgroup 屬性會採用以空格分隔的權杖清單。第一個權杖一律是宣告小工具模式的行為權杖。選用修飾符權杖如下:focusgroup="<behavior> [inline|block] [wrap] [nomemory]"

行為權杖

除非使用 none 選擇退出上層焦點群組,否則必須提供行為權杖。它會宣告複合式小工具模式,確保在未另行指定時,可推斷正確的角色。權杖遵循無障礙網頁 (ARIA) 撰寫實務指南中說明的模式,並列於下表:

行為 APG 模式 最低容器角色 (如適用) 子角色下限
(適用時)
預設修飾符
toolbar 工具列 工具列 (無) inline
tablist APG 分頁 tablist 分頁 inline wrap
radiogroup 單選按鈕群組 radiogroup 電台 (無)
listbox Listbox listbox option (無)
menu 菜單 選單 menuitem block wrap
menubar 功能表列 menubar menuitem inline wrap
none 不適用 不適用 不適用 不適用

如要進一步瞭解角色對應的運作方式,請參閱說明

軸線限制 (inlineblock)

如果所選行為沒有任何預設修飾符,四個方向鍵都能移動焦點。您可以使用 inlineblock 修飾符,將導覽限制為單一邏輯軸:

  • inline:focusgroup 只會回應內嵌軸上的方向鍵,在大多數英文語言環境中為左右鍵 (水平,由上到下)
  • block:focusgroup 只會回應區塊軸上的方向鍵,在大多數英文語言環境中為上下鍵 (水平,由上而下)。

軸向限制會與 CSS 邏輯屬性對齊,並自動配合書寫模式和方向調整。

環繞式導覽

根據預設,箭頭鍵瀏覽會在焦點群組的邊緣停止。新增 wrap 修飾符,從最後一個項目循環回到第一個項目 (以及從第一個項目回到最後一個項目)。如果行為預設會換行,請使用 nowrap 修飾符停用這項行為。

立即試用:Tablist Pattern > Horizontal Tablist with Wrapping。 在該範例中,當焦點位於「常見問題」分頁,且使用者按下向右箭頭鍵時,焦點會返回「總覽」分頁。

focusgroupstart 屬性

focusgroupstart 屬性會標記首次 Tab 鍵進入焦點群組時 (或停用記憶體時每次),哪個元素會取得焦點:

<div focusgroup="toolbar nomemory" aria-label="Entry point demo">
  <button type="button">First</button>
  <button type="button" focusgroupstart>Middle (Entry)</button>
  <button type="button">Last</button>
</div>
功能表列,中間的按鈕處於焦點狀態。

Tab 鍵和 Shift+Tab 鍵都會停留在「Middle (Entry)」,因為該項目有 focusgroupstart,且記憶體已透過 nomemory 修飾符停用。立即試用: 工具列模式 > 具有 focusgroupstart 的進入點

停用記憶功能 (nomemory)

根據預設,focusgroups 會記住上次聚焦的項目,並在重新輸入 Tab 時還原該項目。如果焦點應一律返回固定進入點 (如先前的示範),請在 focusgroup 屬性中使用 nomemory 修飾符停用該屬性。

您也可以將這個修飾符與 focusgroupstart 的程式輔助移動功能結合,全面控管進入群組時的焦點項目。如果記憶的元素無法使用 (例如遭到移除、隱藏、停用、惰性或從焦點群組中排除),系統就會清除記憶體。

停用 (focusgroup="none")

使用 focusgroup="none" 從上層焦點群組的箭頭鍵導覽中排除元素及其子樹狀結構。使用 Tab 鍵仍可存取已停用的元素及其子樹狀結構,但方向鍵會略過這些元素:

<div focusgroup="toolbar" aria-label="Segmented toolbar">
  <button type="button">New</button>
  <button type="button">Open</button>
  <button type="button">Save</button>
  <span focusgroup="none">
    <button type="button">Help</button>
    <button type="button">Shortcuts</button>
  </span>
  <button type="button">Close</button>
  <button type="button">Exit</button>
</div>
「說明」和「快速鍵」按鈕呈現灰色,表示無法使用。

使用向右鍵可依序前往「新增」、「開啟」、「儲存」、「關閉」和「結束」,完全略過「說明」和「快速鍵」按鈕。但使用者仍可按 Tab 鍵進入說明部分,存取這些按鈕。立即試用: 其他概念 > 選擇停用區隔,並將 focusgroup="none"

常見模式

Tablist

分頁控制項,可使用方向鍵在分頁之間移動。

<div focusgroup="tablist nomemory" aria-label="Sections">
  <button type="button" aria-selected="true" aria-controls="panel-overview" id="tab-overview" focusgroupstart>Overview</button>
  <button type="button" aria-selected="false" aria-controls="panel-features" id="tab-features">Features</button>
  <button type="button" aria-selected="false" aria-controls="panel-pricing" id="tab-pricing">Pricing</button>
  <button type="button" aria-selected="false" aria-controls="panel-faq" id="tab-faq">FAQ</button>
</div>
<div role="tabpanel" id="panel-overview" aria-labelledby="tab-overview" tabindex="0">...</div>
<div role="tabpanel" id="panel-features" aria-labelledby="tab-features" tabindex="0">...</div>
<div role="tabpanel" id="panel-pricing" aria-labelledby="tab-pricing" tabindex="0">...</div>
<div role="tabpanel" id="panel-faq" aria-labelledby="tab-faq" tabindex="0">...</div>
總覽分頁處於焦點狀態。

立即試用:Tablist Pattern > Horizontal Tablist with Wrapping

注意:

  • focusgroupstart」屬性位於「已選取」分頁中,因此焦點一律會進入該分頁。
  • nomemory 修飾符可確保即使使用者先前已將焦點放在其他分頁上,重新進入時一律會前往所選分頁。
  • inline 修飾符只會將箭頭鍵導覽限制為向左和向右鍵。這與 APG 分頁模式中列出的預期行為相符。
  • wrap 修飾鍵可讓使用者透過所有分頁標籤,持續使用方向鍵。
  • 為簡潔起見,省略的開發人員程式碼會處理實際選取作業:更新 aria-selected、切換面板顯示設定,以及在選取項目變更時移動 focusgroupstart 屬性。

簡單的直向選單,可使用向上和向下箭頭導覽。

<div focusgroup="menu" aria-label="File actions" class="menu-vertical">
    <button type="button" class="menu-item">New</button>
    <button type="button" class="menu-item">Open…</button>
    <button type="button" class="menu-item">Save</button>
    <button type="button" class="menu-item">Exit</button>
</div>
垂直選單,焦點位於「開啟」選單項目。

即時試用: 選單和選單列模式 > 簡易直向選單。 使用 block 修飾符時,只能使用向上鍵和向下鍵瀏覽項目。向左鍵和向右鍵可自由定義行為 (例如開啟子選單)。如果選單列含有巢狀子選單,每個層級都是獨立的焦點群組。立即試用: 選單和選單列模式 > 含有快顯子選單的選單列

<ul role="menubar" focusgroup="menubar"
     aria-label="Application Menu" class="menubar">
    <li role="none">
        <button role="menuitem" type="button" class="menubar-item"
             aria-haspopup="menu" aria-expanded="false"
             popovertarget="filemenu">File</button>
        <ul role="menu" focusgroup="menu"
             id="filemenu" popover aria-label="File submenu" class="submenu">
            <li role="none"><button type="button" class="submenu-item"
                 autofocus>New</button></li>
            <li role="none"><button type="button" class="submenu-item">Open</button></li>
            <li role="none"><button type="button" class="submenu-item">Save</button></li>
        </ul>
    </li>
    <!-- More menu items... -->
</ul>
下拉式選單,焦點位於「複製」項目。

立即試用: 選單和選單列模式 > 含有快顯子選單的選單列。 menubar 使用 inline 修飾符向左和向右導覽,子選單則使用 block 修飾符向上和向下導覽。巢狀焦點群組完全獨立,因此不會互相干擾。

Radiogroup

自訂圓形按鈕群組,可使用方向鍵瀏覽,並完整控制樣式。

<div focusgroup="radiogroup" aria-label="Favorite color">
  <span aria-checked="false" tabindex="0">Red</span>
  <span aria-checked="false" tabindex="0">Green</span>
  <span aria-checked="true" tabindex="0" focusgroupstart >Blue</span>
  <span aria-checked="false" tabindex="0">Purple</span>
</div>
圓形按鈕群組,焦點位於「藍色」。

立即試用: Radio Group Pattern > Comparison: Native versus Focusgroup

focusgroup 屬性會處理方向鍵導覽,但您必須實作選取程式碼。在本示範中,JavaScript 程式碼會管理勾選狀態 (使用 aria-checked 屬性)。

核心概念

焦點團體項目參與

如果元素的 focusgroup 設為有效行為,該元素的所有可依序聚焦的子項都會視為參與該焦點群組。也就是說,系統不會考量 tabindex 為負值的元素,但會考量原生可聚焦元素 (例如 <button>),以及您指定非負值 tabindex 的元素。

定位點

不需要管理 tabindex。即使多個後代元素自然可透過 Tab 鍵選取 (例如多個 <button> 元素),focusgroup 也會將這些元素收合成單一 Tab 鍵停駐點。瀏覽器會處理在任何特定時間可使用 Tab 鍵選取的項目。試用即時範本: 工具列模式 > 無須管理 tabindex

最後聚焦的記憶體

根據預設,使用者按下 Tab 鍵離開 focusgroup,然後再按 Tab 鍵返回時,焦點會回到上次聚焦的項目。這對大型清單和工具列至關重要,可避免使用者不知道自己讀到哪裡。如要一律將焦點還原至第一個元素,或使用 focusgroupstart 控制最初聚焦的元素,請使用 nomemory 修飾符停用這項行為。

巢狀焦點群組

每個 focusgroup 宣告都會建立獨立範圍。巢狀焦點群組會自動停用其祖先的箭頭鍵導覽功能。使用 Tab 鍵在焦點群組之間移動,並使用方向鍵在目前的焦點群組內移動。立即試用: 其他概念 > 巢狀焦點群組

支援 Shadow DOM

根據預設,Focusgroup 會套用至整個 shadow DOM 邊界。在陰影主機上宣告的焦點群組包含該主機陰影樹狀結構內的可聚焦元素。如要停用,可以在元件的陰影樹狀結構中使用 focusgroup="none"

處理鍵衝突

focusgroup 內的部分元素 (例如 <input><textarea> 和其他控制項) 會基於自身用途使用方向鍵。當焦點群組的導覽鍵與原生元素的箭頭鍵行為發生衝突時:

  • 互動元素會耗用方向鍵 (例如用於移動文字游標),而 focusgroup 不會干擾。
  • Tab 鍵或 Shift+Tab 鍵提供預設逸出機制,讓使用者使用 Tab 鍵導覽「重新進入」焦點群組。

只有在實際發生按鍵衝突時,才會套用這些逸出行為;非衝突軸不會受到影響。您也可以對 keydown 事件呼叫 preventDefault(),覆寫特定元素的焦點群組箭頭鍵行為。也就是說,您可以在 focusgroup 內加入輸入內容和文字區域,而不會中斷任何行為。

如果您將鍵盤事件處理常式新增至參與焦點群組的自有元素,請務必提供類似的逸出機制,讓使用者存取群組的其餘部分。

深層後代探索

Focusgroup 項目不一定要是 focusgroup 容器的直接子項。

瀏覽器會將所有可依序聚焦的後代 (非負數 tabindex) 視為焦點群組的成員,除非這些後代位於巢狀焦點群組中,或使用 focusgroup="none" 選擇不加入。

<div focusgroup="toolbar" aria-label="Nested wrappers">
  <div>
    <span>
      <button type="button">Alpha</button>
    </span>
    <span>
      <button type="button">Beta</button>
    </span>
    <span>
      <button type="button">Gamma</button>
    </span>
  </div>
</div>

即使按鈕巢狀內嵌於 <div><span> 包裝函式中,方向鍵導覽功能仍可正常運作。沒有扁平清單需求,因此樣式包裝函式元素沒問題。

立即試用: 其他概念 > 深層後代

與「reading-flow」資源整合

如果存在 CSS reading-flow 屬性,循序 (Tab 鍵) 和方向 (箭頭鍵) 導覽都會遵循該屬性,按照視覺閱讀順序而非 DOM 來源順序。

確保箭頭鍵導覽功能與使用者在畫面上看到的版面配置一致。

<div focusgroup="toolbar" aria-label="Visual order"
     style="display: flex; flex-direction: row-reverse; reading-flow: flex-visual;">
  <button type="button">A (DOM first)</button>
  <button type="button">B (DOM second)</button>
  <button type="button">C (DOM third)</button>
</div>
焦點在項目 A 上。

雖然 DOM 順序是 A、B、C,但由於版面配置使用 flex-direction: row-reverse,因此視覺順序是 C、B、A。不過,由於程式碼也使用 reading-flow: flex-visual,讀取順序會回到 A、B、C,焦點群組也會符合這個順序。

按下 Tab 鍵會先將焦點移至 C,然後按下向右鍵會將焦點移至 B,最後移至 A。 立即試用: 其他概念 > CSS 讀取流程整合

無障礙設定

ARIA 角色推論

在焦點群組中,瀏覽器會使用行為權杖,推斷容器及其參與項目適用的最低角色。也就是說,當您在具有一般角色的元素上設定 focusgroup 屬性時,系統會根據所選行為套用正確的角色。如果元素參與項目具有一般角色,或按鈕沒有您指定的角色,系統會相應推斷這些項目的角色。舉例來說,下列 HTML:

<div focusgroup="tablist">
  <button>Tab 1</button>
  <button>Tab 2</button>
  <button>Tab 3</button>
</div>

即使按鈕上未定義任何角色,仍會建立下列無障礙功能樹狀結構:

+   tablist
  |
  +   tab
  |
  +   tab
  |
  +   tab

您隨時可以透過直接設定角色來控管行為。

無障礙注意事項

請務必遵守建立焦點群組時選擇的行為。

焦點群組的使用方式應盡可能符合您指定的行為。這項措施可確保依賴無障礙工具的使用者能夠瀏覽內容及使用自訂控制項。

雖然角色推論功能會提供合適的預設值,但使用非一般角色的元素時,請務必確保這些元素已針對提供的功能設定適當的角色。

使用 focusgroup 時,請記得使用者可能需要使用方向鍵捲動才能查看內容。鍵盤使用者應一律能讀取及存取網頁上的內容。

特徵偵測

如要搶先在瀏覽器全面支援 focusgroup 前使用這項功能,可以先在 JavaScript 中偵測 focusgroup 支援情形:

if ('focusgroup' in HTMLElement.prototype) {
  // focusgroup is supported.
} else {
  // fall back to manual roving tabindex.
}

結論

focusgroup 屬性正在通過標準機構的審查,我們也積極在 Chromium 中建構原型,並改善 API。

歡迎試用,並在 Open-UI GitHub 問題追蹤器中回報焦點團體問題。我們特別想瞭解您對下列項目的看法:

  • API 介面是否適合您建構的模式?
  • 是否有我們遺漏的模式或情境?
  • 是否有不應允許 focusgroup 屬性的元素?
  • 無障礙故事如何適用於您的用途?

感謝你協助改善網頁的鍵盤導覽功能!

瞭解詳情

感謝 Mason Freed、Sara Higley、Scott O'Hara 和 Open-UI 社群的協助,讓 focusgroup 回歸。