Dipublikasikan: 5 Maret 2026
Atribut HTML focusgroup adalah cara deklaratif yang diusulkan untuk menambahkan navigasi tombol panah keyboard ke widget komposit seperti toolbar, tablist, menu, listbox, dll. tanpa menulis JavaScript roving-tabindex. Satu atribut
menggantikan ratusan baris boilerplate. Kami ingin mendengar masukan Anda sebelum fitur ini diluncurkan.
Cobalah dan sampaikan masukan Anda kepada kami
Anda dapat mencoba focusgroup hari ini di Chrome, Edge, dan browser berbasis Chromium lainnya dengan mengaktifkannya melalui salah satu dari dua cara berikut:
- Pengujian lokal: Di browser, buka halaman
about://flagsdan aktifkan tanda Fitur Platform Web Eksperimental. Atau, luncurkan browser dari command line dengan menggunakan parameter command line--enable-blink-features=Focusgroup. - Uji coba origin: Daftar untuk uji coba origin focusgroup untuk mengujinya di situs Anda dengan pengguna sungguhan.
Kemudian, pelajari demo interaktif untuk melihat cara kerja setiap pola.
Kami memerlukan masukan Anda. Ajukan masalah grup fokus untuk menyampaikan pendapat Anda.
Ini adalah upaya lintas browser: proposal ini berasal dari Microsoft melalui Grup Komunitas OpenUI dengan dukungan kuat dari Google. Struktur API dapat berubah berdasarkan masukan Anda. Mari kita pelajari masalah yang diselesaikan oleh grup fokus dan cara kerja API.
Masalah: indeks tab jelajah manual
Jika Anda pernah membuat toolbar, tablist, menu, atau listbox, Anda telah menulis beberapa versi kode ini. Panduan Praktik Penulisan ARIA (APG) merekomendasikan agar widget komposit menampilkan satu Tab stop dan memungkinkan pengguna berpindah antar-item dengan tombol panah. Pola ini dikenal sebagai "tabindex bergerak". Banyak framework UI yang mengimplementasikan ulang hal ini dari awal:
<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>
Dari sini, developer perlu menggunakan JavaScript yang memproses tombol panah untuk memindahkan fokus, dan menyesuaikan atribut tabindex untuk semua elemen. Ini adalah versi sederhana. Implementasi produksi juga perlu menangani:
- Mode penulisan dan RTL: Menyesuaikan arah tombol panah berdasarkan arah konten.
- Memori fokus terakhir: Memulihkan fokus ke item yang sebelumnya aktif saat pengguna kembali ke Tab.
- Item yang dinonaktifkan dan disembunyikan: Dilewati selama navigasi.
- Item dinamis: Perbarui indeks roaming saat item ditambahkan atau dihapus.
Sebagian besar library UI, termasuk React, Angular CDK, dan Fluent UI, masing-masing mengirimkan versi logika ini sendiri. Ada banyak upaya duplikat untuk mendapatkan sesuatu yang bisa menjadi primitif platform.
Solusi: atribut focusgroup
Dengan focusgroup, toolbar yang sama menjadi:
<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>
Coba secara langsung: Pola Toolbar > Toolbar Dasar. Selesai. Tidak ada JavaScript untuk navigasi tombol panah. Tidak ada pengelolaan tabindex manual. Berikut yang kini ditangani browser untuk Anda:
- Navigasi tombol panah: Beralih antar-item, sambil memperhatikan mode dan arah penulisan.
- Satu Perhentian tab: Browser akan menciutkan item yang berpartisipasi menjadi satu
Perhentian tab secara otomatis. Developer tidak perlu menetapkan
tabindex="-1"pada item yang tidak aktif. - Memori fokus terakhir: Saat pengguna keluar dari focusgroup dan kembali, fokus dipulihkan ke item yang ditinggalkannya.
- Semantik ARIA: Browser menyediakan peran yang sesuai (seperti
role="toolbar") berdasarkan perilaku yang dipilih saat elemen generik digunakan.
Developer hanya menyimpan logika yang unik untuk fitur mereka seperti mengubah status ditekan, membuka menu, mengelola pilihan, atau perintah kustom apa pun.
Ringkasan API
Atribut focusgroup mengambil daftar token yang dipisahkan spasi. Token
pertama selalu berupa token perilaku yang mendeklarasikan pola widget. Token pengubah
opsional adalah sebagai berikut: focusgroup="<behavior> [inline|block] [wrap] [nomemory]".
Token perilaku
Token perilaku diperlukan (kecuali jika menggunakan none untuk memilih tidak ikut grup fokus induk). Pola widget komposit dideklarasikan, sehingga memastikan bahwa peran yang tepat dapat disimpulkan jika tidak ditentukan. Token mengikuti pola yang dijelaskan dalam panduan Praktik Penulisan Aria dan tercantum dalam tabel berikut:
| Perilaku | Pola APG | Peran minimum penampung (jika diterapkan) | Peran turunan minimum (jika diterapkan) |
Pengubah default |
|---|---|---|---|---|
toolbar |
Toolbar | toolbar | (tidak ada) | inline |
tablist |
Tab APG | tablist | tab | inline wrap |
radiogroup |
Grup Radio | radiogroup | radio | (tidak ada) |
listbox |
Kotak daftar | listbox | option | (tidak ada) |
menu |
Menu | menu | menuitem | block wrap |
menubar |
Menubar | menubar | menuitem | inline wrap |
none |
t/a | t/a | t/a | t/a |
Lihat penjelasan untuk mengetahui detail lengkap tentang cara kerja pemetaan peran.
Pembatasan sumbu (inline dan block)
Jika perilaku yang dipilih tidak memiliki pengubah default, keempat tombol panah akan berfungsi untuk memindahkan fokus. Anda dapat membatasi navigasi ke satu sumbu logis dengan
menggunakan pengubah inline atau block:
inline: focusgroup hanya merespons tombol panah pada sumbu inline, kiri dan kanan dalam sebagian besar konteks bahasa Inggris (horizontal, atas ke bawah).block: focusgroup hanya merespons tombol panah pada sumbu blok, atas dan bawah dalam sebagian besar konteks bahasa Inggris (horizontal, atas ke bawah).
Pembatasan sumbu selaras dengan properti logis CSS dan otomatis beradaptasi dengan mode dan arah penulisan.
Navigasi wrap-around
Secara default, navigasi tombol panah berhenti di tepi focusgroup. Tambahkan pengubah
wrap untuk melakukan loop dari item terakhir kembali ke item pertama (dan dari item pertama
kembali ke item terakhir). Jika perilaku memiliki pembungkusan secara default, gunakan pengubah nowrap untuk menonaktifkan perilaku ini.
Coba langsung: Tablist Pattern > Horizontal Tablist with Wrapping. Dalam contoh tersebut, saat fokus berada di tab FAQ dan pengguna menekan tombol panah Kanan, fokus akan kembali ke tab Ringkasan.
Atribut focusgroupstart
Atribut focusgroupstart menandai elemen mana yang menerima fokus saat melakukan Tab
ke dalam focusgroup untuk pertama kalinya (atau setiap kali saat memori dinonaktifkan):
<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 dan Shift+Tab mendarat di "Middle (Entry)" karena memiliki focusgroupstart
dan memori dinonaktifkan dengan pengubah nomemory. Coba secara langsung:
Pola Toolbar > Titik Entri dengan focusgroupstart.
Nonaktifkan memori (nomemory)
Secara default, focusgroup mengingat item yang terakhir difokuskan dan memulihkannya saat
masuk kembali dengan Tab. Untuk pola yang fokusnya harus selalu kembali ke titik
entri tetap (seperti dalam demo sebelumnya), gunakan pengubah nomemory di atribut
focusgroup untuk menonaktifkannya.
Pengubah ini juga dapat digabungkan dengan gerakan terprogram
focusgroupstart untuk memberi Anda kontrol penuh atas item yang difokuskan saat
memasuki grup. Memori akan dibersihkan saat elemen yang diingat menjadi
tidak tersedia; misalnya, jika elemen tersebut dihapus, disembunyikan, dinonaktifkan, tidak aktif, atau dikecualikan
dari focusgroup.
Memilih tidak ikut (focusgroup="none")
Gunakan focusgroup="none" untuk mengecualikan elemen dan subtre-nya dari navigasi panah focusgroup induk. Elemen yang tidak diikutsertakan dan subpohonnya tetap dapat dijangkau menggunakan Tab, tetapi tombol panah akan melewatinya:
<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>
Menggunakan tombol panah kanan akan membuka opsi Baru, lalu Buka, Simpan, Tutup, dan Keluar, serta melewati tombol Bantuan dan Pintasan. Namun, pengguna tetap dapat menekan Tab untuk membuka bagian bantuan guna mengakses tombol ini. Coba secara langsung: Konsep Tambahan > Segmen yang Tidak Bersedia dengan focusgroup="none".
Pola umum
Tablist
Kontrol tab dengan navigasi tombol panah di antara tab.
<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>
Coba langsung: Tablist Pattern > Horizontal Tablist with Wrapping.
Hal yang perlu diperhatikan:
- Atribut
focusgroupstartada di tab selected, sehingga fokus selalu masuk ke sana. - Pengubah
nomemorymemastikan bahwa meskipun pengguna sebelumnya telah memfokuskan pada tab yang berbeda, entri ulang selalu menuju ke tab yang dipilih. - Pengubah
inlinemembatasi navigasi panah hanya ke tombol kiri dan kanan. Hal ini sesuai dengan perilaku yang diharapkan yang diuraikan oleh pola Tab APG. - Pengubah
wrapmemungkinkan pengguna menggunakan tombol panah secara terus-menerus di semua tab. - Kode developer, yang dihilangkan agar lebih ringkas, menangani pilihan sebenarnya: memperbarui
aria-selected, mengganti visibilitas panel, dan memindahkan atributfocusgroupstartpada perubahan pilihan.
Menu dan panel menu
Menu vertikal sederhana dengan navigasi panah atas dan bawah.
<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>
Coba langsung:
Pola Menu dan Menu Bar > Menu Vertikal Sederhana.
Dengan pengubah block, hanya tombol panah atas dan bawah yang dapat menavigasi item. Tombol panah kiri dan kanan bebas untuk perilaku yang Anda tentukan (misalnya, membuka submenu). Untuk menubar dengan submenu bertingkat, setiap level adalah
grup fokus independen. Coba langsung:
Pola Menu dan Panel menu > Panel menu dengan Submenu Popover
<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>
Coba langsung:
Pola Menu dan Menu Bar > Menu Bar dengan Submenu Popover.
Meskipun menubar menggunakan pengubah inline untuk navigasi kiri dan kanan, submenu menggunakan pengubah block untuk navigasi atas dan bawah. Grup fokus bertingkat
benar-benar independen sehingga tidak saling mengganggu.
Radiogroup
Grup tombol pilihan kustom dengan navigasi tombol panah dan kontrol gaya penuh.
<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>
Coba langsung: Pola Grup Radio > Perbandingan: Native versus Focusgroup.
Meskipun atribut focusgroup menangani navigasi tombol panah, Anda harus
menerapkan kode pemilihan. Dalam demo ini, kode JavaScript mengelola status
yang dicentang (dengan menggunakan atribut aria-checked).
Konsep utama
Partisipasi item grup fokus
Semua turunan yang dapat difokuskan secara berurutan dari elemen dengan focusgroup yang ditetapkan ke perilaku yang valid dianggap berpartisipasi dalam grup fokus tersebut. Artinya, elemen dengan tabindex negatif tidak dipertimbangkan, tetapi elemen yang dapat difokuskan secara native seperti <button>, serta elemen tempat Anda menentukan tabindex non-negatif, akan dipertimbangkan.
Tab stop
Anda tidak perlu mengelola nilai tabindex. Meskipun beberapa turunan
dapat di-tab secara alami (misalnya, beberapa elemen <button>), focusgroup
akan menciutkannya menjadi satu Tab stop. Browser menangani item mana yang dapat difokuskan dengan tombol tab pada waktu tertentu. Coba secara live:
Pola Toolbar > Tidak Perlu Pengelolaan tabindex.
Memori yang terakhir difokuskan
Secara default, saat pengguna menekan Tab untuk keluar dari focusgroup dan kemudian menekan Tab kembali, fokus akan kembali ke item yang terakhir difokuskan. Hal ini sangat penting untuk daftar dan
toolbar yang besar agar pengguna tidak kehilangan bagian yang sedang mereka lihat. Gunakan pengubah nomemory untuk menonaktifkan
perilaku ini jika Anda ingin fokus selalu dipulihkan ke elemen pertama, atau
jika Anda menggunakan focusgroupstart, untuk mengontrol elemen yang difokuskan pada awalnya.
Grup fokus bertingkat
Setiap deklarasi focusgroup membuat cakupan independen. Grup fokus bertingkat secara otomatis menonaktifkan navigasi panah induknya. Gunakan Tab untuk berpindah-pindah antar-grup fokus, dan tombol panah untuk menjelajahi dalam grup fokus saat ini. Coba secara langsung: Konsep Tambahan > Grup Fokus Bertingkat.
Dukungan Shadow DOM
Focusgroup diterapkan di seluruh batas DOM bayangan secara default. Grup fokus yang dideklarasikan di host bayangan mencakup elemen yang dapat difokuskan di dalam hierarki bayangan host tersebut. Jika ingin memilih tidak ikut, Anda dapat menggunakan focusgroup="none" di dalam shadow tree komponen.
Penanganan konflik kunci
Beberapa elemen di dalam focusgroup, seperti <input>, <textarea>, dan kontrol
lainnya menggunakan tombol panah untuk tujuan mereka sendiri. Jika ada konflik antara tombol navigasi grup fokus dan perilaku tombol panah elemen native:
- Tombol panah digunakan oleh elemen interaktif (misalnya, untuk pergerakan kursor teks), dan focusgroup tidak mengganggu.
- Tab atau Shift+Tab menyediakan mekanisme keluar default, yang memungkinkan pengguna menggunakan navigasi Tab untuk "masuk kembali" ke focusgroup.
Perilaku pelepasan ini hanya berlaku jika ada konflik tombol aktual;
sumbu yang tidak berkonflik tidak terpengaruh. Anda juga dapat memanggil preventDefault() pada
peristiwa keydown untuk mengganti perilaku tombol panah focusgroup untuk elemen
tertentu. Artinya, Anda dapat menyertakan input dan textarea di dalam
focusgroup tanpa merusak perilaku tersebut.
Jika Anda menambahkan pengendali tombol ke elemen Anda sendiri yang berpartisipasi dalam grup fokus, berhati-hatilah untuk menyediakan mekanisme keluar yang serupa sehingga pengguna dapat mengakses grup lainnya.
Penemuan turunan mendalam
Item focusgroup tidak harus berupa turunan langsung dari penampung focusgroup.
Browser menganggap semua turunan yang dapat difokuskan secara berurutan (non-negatif
tabindex) berpartisipasi dalam focusgroup, kecuali jika berada di dalam focusgroup bertingkat
atau tidak diikutsertakan dengan 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>
Navigasi tombol panah berfungsi meskipun tombol disarangkan di dalam wrapper <div> dan
<span>. Tidak ada persyaratan daftar datar, sehingga elemen wrapper untuk
penataan gaya tidak masalah.
Coba secara langsung: Konsep Tambahan > Turunan Dalam.
Integrasi dengan properti reading-flow
Navigasi berurutan (Tab) dan terarah (tombol panah) mematuhi properti CSS
reading-flow jika ada, mengikuti urutan baca visual, bukan
urutan sumber DOM.
Hal ini memastikan bahwa navigasi tombol panah cocok dengan tata letak yang dilihat pengguna di layar.
<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>
Meskipun urutan DOM adalah A, B, C, urutan visualnya adalah C, B, A karena tata letaknya
menggunakan flex-direction: row-reverse. Namun, karena kode juga menggunakan
reading-flow: flex-visual, urutan pembacaan kembali menjadi A, B, C, dan
grup fokus cocok dengan urutan ini.
Menekan Tab akan memfokuskan C terlebih dahulu, lalu menekan kanan akan memfokuskan B, lalu A. Coba langsung: Additional Concepts > CSS reading-flow Integration.
Aksesibilitas
Inferensi Peran ARIA
Dalam grup fokus, token perilaku digunakan oleh browser untuk menyimpulkan peran minimum bagi penampung dan item yang berpartisipasi di dalamnya. Artinya, saat
atribut focusgroup ditetapkan pada elemen yang memiliki peran generik, peran
yang benar, berdasarkan perilaku yang dipilih, akan diterapkan. Item yang berpartisipasi dalam elemen yang memiliki peran umum, atau tombol yang tidak memiliki peran yang Anda tentukan, akan memiliki peran yang disimpulkan secara sesuai. Misalnya, HTML
berikut:
<div focusgroup="tablist">
<button>Tab 1</button>
<button>Tab 2</button>
<button>Tab 3</button>
</div>
Membuat hierarki aksesibilitas berikut, meskipun tidak ada peran yang ditentukan pada tombol:
+ tablist
|
+ tab
|
+ tab
|
+ tab
Anda selalu dapat mengontrol perilaku dengan menetapkan peran secara langsung.
Pertimbangan aksesibilitas
Pastikan untuk menghormati perilaku yang Anda pilih saat membuat grup fokus.
Penggunaan Focusgroup harus disesuaikan sedekat mungkin dengan perilaku yang Anda tentukan. Hal ini penting untuk memastikan bahwa pengguna yang mengandalkan alat aksesibilitas dapat menjelajahi konten dan menggunakan kontrol kustom.
Meskipun inferensi peran memberikan default yang baik, saat menggunakan elemen dengan peran non-generik, berhati-hatilah untuk memastikan bahwa elemen tersebut memiliki setelan peran yang tepat untuk fungsi yang mereka berikan.
Saat menggunakan focusgroup, ingatlah bahwa pengguna mungkin perlu dapat men-scroll dengan tombol panah untuk melihat konten Anda. Pengguna keyboard harus selalu dapat membaca dan mengakses konten di halaman Anda.
Deteksi fitur
Untuk mulai menggunakan focusgroup hari ini, sebelum didukung sepenuhnya di seluruh browser, Anda dapat mendeteksi dukungan focusgroup di JavaScript:
if ('focusgroup' in HTMLElement.prototype) {
// focusgroup is supported.
} else {
// fall back to manual roving tabindex.
}
Kesimpulan
Atribut focusgroup sedang diproses oleh badan standar, dan kami
secara aktif membangun prototipe di Chromium dan menyempurnakan API.
Coba dan ajukan masalah grup fokus di issue tracker GitHub Open-UI. Kami sangat tertarik dengan pendapat Anda tentang hal-hal berikut:
- Apakah platform API terasa tepat untuk pola yang Anda buat?
- Apakah ada pola atau skenario yang terlewat?
- Apakah ada elemen yang tidak boleh memiliki atribut focusgroup?
- Bagaimana cara kerja kisah aksesibilitas untuk kasus penggunaan Anda?
Terima kasih telah membantu meningkatkan kualitas navigasi keyboard di web.
Pelajari lebih lanjut
- Penjelasan Focusgroup
- Demo Interaktif (sumber)
- Masalah HTML WHATWG
- Open UI Focusgroup Issues
- ARIA Authoring Practices Guide
Terima kasih kepada Mason Freed, Sara Higley, Scott O'Hara, dan komunitas Open-UI lainnya atas bantuan mereka dalam menghadirkan kembali focusgroup.