diff --git a/src/react/SimulationFilter.tsx b/src/react/SimulationFilter.tsx
index 26cffa6..89bf9df 100644
--- a/src/react/SimulationFilter.tsx
+++ b/src/react/SimulationFilter.tsx
@@ -11,7 +11,7 @@ import {
isVisionMode,
} from '../core/constants/modes.js';
import { VisionMode, VisionOptions } from '../types/simulationTypes.js';
-import { useEffect, useRef, useState } from 'react';
+import { useEffect, useId, useRef, useState } from 'react';
import { SimulationKey, useTheme } from './ThemeProvider.js';
import { VisionFilterPortal } from './VisionPortal.js';
import { TOOLBAR_POSITION } from '../core/constants/position.js';
@@ -65,6 +65,7 @@ export default function SimulationFilter(props?: SimulationFilterProps) {
const [open, setOpen] = useState(false);
const { simulationFilter, setSimulationFilter, language } = useTheme();
const initialized = useRef(false);
+ const optionsId = useId();
if (!visible) return null;
if (!allowInProd && !IS_DEV) return null;
@@ -169,37 +170,83 @@ export default function SimulationFilter(props?: SimulationFilterProps) {
-
);
diff --git a/src/react/ThemeSwitcher.tsx b/src/react/ThemeSwitcher.tsx
index d07c5a3..10e76d1 100644
--- a/src/react/ThemeSwitcher.tsx
+++ b/src/react/ThemeSwitcher.tsx
@@ -1,6 +1,6 @@
'use client';
-import React, { useEffect, useRef, useState, useMemo } from 'react';
+import React, { useEffect, useId, useMemo, useRef, useState } from 'react';
import { useTheme, getThemeOptions, type ThemeKey } from './ThemeProvider.js';
import Logo from '../icons/Logo.js';
import US from '../icons/Us.js';
@@ -38,6 +38,7 @@ export function ThemeSwitcher({ options, position }: TThemeSwitcherProps) {
);
const [isOpen, setIsOpen] = useState(false);
const wrapperRef = useRef(null);
+ const menuId = useId();
const switcherClass = SWITCHER_POSITION[position ?? 'right-bottom'];
const switcherMenuClass =
@@ -62,6 +63,15 @@ export function ThemeSwitcher({ options, position }: TThemeSwitcherProps) {
setIsOpen((prev) => !prev);
};
+ const toggleAriaLabel =
+ language === 'Korean'
+ ? isOpen
+ ? '테마 전환 메뉴 닫기'
+ : '테마 전환 메뉴 열기'
+ : isOpen
+ ? 'Close theme switcher menu'
+ : 'Open theme switcher menu';
+
return (
@@ -71,6 +81,8 @@ export function ThemeSwitcher({ options, position }: TThemeSwitcherProps) {
type="button"
aria-haspopup="menu"
aria-expanded={isOpen}
+ aria-controls={menuId}
+ aria-label={toggleAriaLabel}
onClick={toggle}
className={`fixed w-[60px] h-[60px] p-[10px] ${isOpen ? 'bg-[#252525] border-[1px] border-[#8144FF]' : 'bg-[rgba(129,68,255,0.2)]'} rounded-full flex justify-center items-center shadow-[0_0_3px_0_rgba(0,0,0,0.17)]
${switcherClass}
@@ -78,7 +90,11 @@ export function ThemeSwitcher({ options, position }: TThemeSwitcherProps) {
>
{isOpen ? (
-
+
) : (
{isOpen ? (
) : (
-
+
)}
@@ -112,6 +133,7 @@ export function ThemeSwitcher({ options, position }: TThemeSwitcherProps) {