From 76ebd93da1dce807c117c9889415ed09e1ddbc4d Mon Sep 17 00:00:00 2001 From: Shelby Level <16slevel@gmail.com> Date: Thu, 17 Sep 2026 11:37:08 -0500 Subject: [PATCH 1/3] Fixes #1354 added aria-controls to navbar navigation list object --- R/navs-legacy.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/navs-legacy.R b/R/navs-legacy.R index 573952e25..b942156b0 100644 --- a/R/navs-legacy.R +++ b/R/navs-legacy.R @@ -790,6 +790,7 @@ liTag <- function(id, title, value, icon) { # data-bs-* is for BS5+ `data-bs-toggle` = "tab", `data-value` = value, + `aria-controls` = id, disabled = if (is_hidden) NA, icon, title From cf606ccc8aa78b970a5e2a49a0cc08f27cb4bb3d Mon Sep 17 00:00:00 2001 From: Shelby Level <16slevel@gmail.com> Date: Thu, 17 Sep 2026 11:45:36 -0500 Subject: [PATCH 2/3] updated NEWS.md file --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 37bee9730..120dd60cb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,6 +16,8 @@ * Navsets created with an `id` (e.g. `navset_tab(id = "tabs")`) now use that `id` as their `data-tabsetid`, so their tab panes get stable `tab-tabs-1` style DOM ids instead of ones derived from a random integer. This makes the rendered markup reproducible across renders and easier to target from custom CSS and JavaScript. Navsets without an `id`, and `nav_menu()` dropdowns, keep the random ID. (#1342) +* Added an aria-controls attribute when using bslib::page_navbar() with bslib::nav_panel() to establish an explicit relationship between the tab and the controlled tab panel. (@shelbylevel, #1354) + # bslib 0.12.0 ## New features From c43075fb4ecef658b92c044f65107014f82a454e Mon Sep 17 00:00:00 2001 From: Shelby Level <16slevel@gmail.com> Date: Thu, 17 Sep 2026 13:04:00 -0500 Subject: [PATCH 3/3] added unit test to check that the `aria-controls` attribute is present in the rendered HTML for a tabset with an id. --- tests/testthat/test-navs-legacy.R | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testthat/test-navs-legacy.R b/tests/testthat/test-navs-legacy.R index 23feabe40..9f3dc49a2 100644 --- a/tests/testthat/test-navs-legacy.R +++ b/tests/testthat/test-navs-legacy.R @@ -175,6 +175,7 @@ test_that("a tabset with an id uses it as the tabset id", { expect_equal(tabset_ids_of(x), c("my_tabs", "my_tabs")) expect_true(grepl('id="tab-my_tabs-1"', html, fixed = TRUE)) expect_true(grepl('href="#tab-my_tabs-1"', html, fixed = TRUE)) + expect_true(grepl('aria-controls="tab-my_tabs-1"', html, fixed = TRUE)) }) test_that("a tabset with an id renders identically every time", {