diff --git a/app/components/DS/tabs.rb b/app/components/DS/tabs.rb index a2c0ff95e..5a0f735be 100644 --- a/app/components/DS/tabs.rb +++ b/app/components/DS/tabs.rb @@ -5,6 +5,7 @@ class DS::Tabs < DesignSystemComponent active_btn_classes: active_btn_classes, inactive_btn_classes: inactive_btn_classes, btn_classes: base_btn_classes, + dom_prefix: dom_prefix, classes: unstyled? ? classes : class_names(nav_container_classes, classes) ) end @@ -13,16 +14,35 @@ class DS::Tabs < DesignSystemComponent content_tag( :div, class: ("hidden" unless tab_id == active_tab), + role: "tabpanel", + id: panel_dom_id(tab_id), + "aria-labelledby": tab_dom_id(tab_id), + tabindex: "0", data: { id: tab_id, DS__tabs_target: "panel" }, &block ) end + # Scope tab/panel DOM ids to this component instance so multiple + # `DS::Tabs` widgets on the same page (which often reuse generic + # tab ids like "all" or "overview") don't collide and break the + # `aria-controls` / `aria-labelledby` associations. + def tab_dom_id(tab_id) + "#{dom_prefix}-tab-#{tab_id}" + end + + def panel_dom_id(tab_id) + "#{dom_prefix}-panel-#{tab_id}" + end + VARIANTS = { default: { - active_btn_classes: "bg-white theme-dark:bg-gray-700 text-primary shadow-sm", + # `tab-item-active` is a Sure token utility (white light / gray-700 dark). + # Swapping out the raw `bg-white theme-dark:bg-gray-700` removes the + # last raw-palette reference in DS::Tabs. + active_btn_classes: "tab-item-active text-primary shadow-sm", inactive_btn_classes: "text-secondary hover:bg-surface-inset-hover", - base_btn_classes: "w-full inline-flex justify-center items-center text-sm font-medium px-2 py-1 rounded-md transition-colors duration-200", + base_btn_classes: "w-full inline-flex justify-center items-center text-sm font-medium px-2 py-1 rounded-md motion-safe:transition-colors motion-safe:duration-200", nav_container_classes: "flex bg-surface-inset p-1 rounded-lg mb-4" } } @@ -48,6 +68,10 @@ class DS::Tabs < DesignSystemComponent end private + def dom_prefix + @dom_prefix ||= "tabs-#{object_id}" + end + def unstyled? variant == :unstyled end diff --git a/app/components/DS/tabs/nav.rb b/app/components/DS/tabs/nav.rb index 8e795588d..eb77672fa 100644 --- a/app/components/DS/tabs/nav.rb +++ b/app/components/DS/tabs/nav.rb @@ -1,6 +1,16 @@ class DS::Tabs::Nav < DesignSystemComponent erb_template <<~ERB - <%= tag.nav class: classes do %> + <%# Neutral `
` host for `role="tablist"`. Per ARIA-in-HTML, + `