From 0293ad9e47f432e69852af2ee62cb819309db1cf Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Wed, 13 Aug 2025 05:07:28 +0530
Subject: [PATCH] fix(a11y): add correct `aria-label` on `ThemeToggle` button
(#8045)
* fix aria-label a11y
* fix test
* add a11y test for aria-label
* fix i18n aria-label text
* fix hydration
* refactor test
* fix test
* Exclude ThemeToggle btn from SSR
---
apps/site/components/withNavBar.tsx | 18 +++++++++--
apps/site/tests/e2e/general-behavior.spec.ts | 31 ++++++++++++++-----
packages/i18n/src/locales/en.json | 3 +-
.../src/Containers/NavBar/index.module.css | 6 ++++
4 files changed, 47 insertions(+), 11 deletions(-)
diff --git a/apps/site/components/withNavBar.tsx b/apps/site/components/withNavBar.tsx
index 8cab6b824c919..24ca3d9d794f2 100644
--- a/apps/site/components/withNavBar.tsx
+++ b/apps/site/components/withNavBar.tsx
@@ -2,7 +2,6 @@
import LanguageDropdown from '@node-core/ui-components/Common/LanguageDropDown';
import Skeleton from '@node-core/ui-components/Common/Skeleton';
-import ThemeToggle from '@node-core/ui-components/Common/ThemeToggle';
import NavBar from '@node-core/ui-components/Containers/NavBar';
// TODO(@AvivKeller): I don't like that we are importing styles from another module
import styles from '@node-core/ui-components/Containers/NavBar/index.module.css';
@@ -27,6 +26,16 @@ const SearchButton = dynamic(() => import('#site/components/Common/Search'), {
),
});
+const ThemeToggle = dynamic(
+ () => import('@node-core/ui-components/Common/ThemeToggle'),
+ {
+ ssr: false,
+ loading: () => (
+
+ ),
+ }
+);
+
const WithNavBar: FC = () => {
const { navigationItems } = useSiteNavigation();
const { resolvedTheme, setTheme } = useTheme();
@@ -39,6 +48,11 @@ const WithNavBar: FC = () => {
const toggleCurrentTheme = () =>
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark');
+ const themeToggleAriaLabel =
+ resolvedTheme === 'dark'
+ ? t('components.common.themeToggle.light')
+ : t('components.common.themeToggle.dark');
+
const changeLanguage = (locale: SimpleLocaleConfig) =>
replace(pathname!, { locale: locale.code });
@@ -63,7 +77,7 @@ const WithNavBar: FC = () => {
- page.evaluate(() => document.documentElement.dataset.theme);
+ page.evaluate(
+ () => document.documentElement.dataset.theme as 'light' | 'dark'
+ );
+
+const getCurrentAriaLabel = (theme: string) =>
+ theme === 'dark'
+ ? locators.themeToggleAriaLabels.light
+ : locators.themeToggleAriaLabels.dark;
const openLanguageMenu = async (page: Page) => {
const button = page.getByRole('button', {
@@ -65,21 +74,27 @@ test.describe('Node.js Website', () => {
test.describe('Theme', () => {
test('should toggle between light/dark themes', async ({ page }) => {
const themeToggle = page.getByRole('button', {
- name: locators.themeToggleName,
+ name: /Switch to (Light|Dark) Mode/i,
});
- await expect(themeToggle).toBeVisible();
const initialTheme = await getTheme(page);
+ const initialAriaLabel = getCurrentAriaLabel(initialTheme);
+ let currentAriaLabel = await themeToggle.getAttribute('aria-label');
+ expect(currentAriaLabel).toBe(initialAriaLabel);
+
await themeToggle.click();
const newTheme = await getTheme(page);
- expect(newTheme).not.toEqual(initialTheme);
- expect(['light', 'dark']).toContain(newTheme);
+ const newAriaLabel = getCurrentAriaLabel(newTheme);
+ currentAriaLabel = await themeToggle.getAttribute('aria-label');
+
+ expect(newTheme).not.toBe(initialTheme);
+ expect(currentAriaLabel).toBe(newAriaLabel);
});
test('should persist theme across page navigation', async ({ page }) => {
const themeToggle = page.getByRole('button', {
- name: locators.themeToggleName,
+ name: /Switch to (Light|Dark) Mode/i,
});
await themeToggle.click();
const selectedTheme = await getTheme(page);
diff --git a/packages/i18n/src/locales/en.json b/packages/i18n/src/locales/en.json
index cadcca42859f3..5465c88e9882e 100644
--- a/packages/i18n/src/locales/en.json
+++ b/packages/i18n/src/locales/en.json
@@ -229,7 +229,8 @@
"label": "Choose Language"
},
"themeToggle": {
- "label": "Toggle Dark Mode"
+ "light": "Switch to Light Mode",
+ "dark": "Switch to Dark Mode"
}
},
"metabar": {
diff --git a/packages/ui-components/src/Containers/NavBar/index.module.css b/packages/ui-components/src/Containers/NavBar/index.module.css
index 331f63f46d83c..764c0edd5ec7a 100644
--- a/packages/ui-components/src/Containers/NavBar/index.module.css
+++ b/packages/ui-components/src/Containers/NavBar/index.module.css
@@ -108,6 +108,12 @@ span.searchButtonSkeleton {
}
}
+span.themeToggleSkeleton {
+ @apply size-9
+ rounded-md
+ py-4;
+}
+
.ghIconWrapper {
@apply size-9
rounded-md