diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 00000000..838910cd --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,9 @@ +## 2024-05-15 - [Initial] + +**Learning:** [Initial file creation] +**Action:** [N/A] + +## 2024-05-15 - [Toggle Buttons Accessibility] + +**Learning:** Elements functioning as standalone toggle buttons must use the `aria-pressed` attribute to indicate their toggled state to screen readers, allowing users to understand when a button is selected or active. +**Action:** Consistently add `aria-pressed` to toggle buttons instead of relying only on visual selection state. diff --git a/src/components/dashboard/filter-pills.tsx b/src/components/dashboard/filter-pills.tsx index d09effbe..02a4fb30 100644 --- a/src/components/dashboard/filter-pills.tsx +++ b/src/components/dashboard/filter-pills.tsx @@ -35,6 +35,7 @@ export function FilterPills({ options, selected, onToggle, onClear, className }: key={option.id} onClick={() => onToggle(option.id)} transition={{ duration: 0.15 }} + aria-pressed={isSelected} className={cn( 'inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-medium transition-all', isSelected diff --git a/tests/filter-pills.spec.tsx b/tests/filter-pills.spec.tsx new file mode 100644 index 00000000..4e8a28a6 --- /dev/null +++ b/tests/filter-pills.spec.tsx @@ -0,0 +1,17 @@ +import { test, expect } from 'vitest' +import { render, screen, fireEvent } from '@testing-library/react' +import { FilterPills } from '../src/components/dashboard/filter-pills' + +test('FilterPills have proper ARIA attributes for toggle state', () => { + const options = [ + { id: 'opt1', label: 'Option 1' }, + { id: 'opt2', label: 'Option 2' }, + ] + render( {}} />) + + const btn1 = screen.getByText('Option 1').closest('button') + const btn2 = screen.getByText('Option 2').closest('button') + + expect(btn1?.getAttribute('aria-pressed')).toBe('true') + expect(btn2?.getAttribute('aria-pressed')).toBe('false') +})