-
-
Notifications
You must be signed in to change notification settings - Fork 6
🎨 Palette: Header Accessibility and Tooltips #538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
|
|
||
| ## 2026-02-20 - [Accessible Header Actions] | ||
| **Learning:** Icon-only buttons in the navigation header lack clear visual and screen-reader context. While ARIA labels solve accessibility, they don't provide visual guidance for sighted users on hover. | ||
| **Action:** Always pair ARIA labels with Tooltips for icon-only navigation elements. Ensure a global TooltipProvider is available in the root layout to support these components. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ import { CalendarToggleProvider } from '@/components/calendar-toggle-context' | |
| import { HistoryToggleProvider } from '@/components/history-toggle-context' | ||
| import { HistorySidebar } from '@/components/history-sidebar' | ||
| import { MapLoadingProvider } from '@/components/map-loading-context'; | ||
| import { TooltipProvider } from '@/components/ui/tooltip' | ||
| import ConditionalLottie from '@/components/conditional-lottie'; | ||
| import { MapProvider as MapContextProvider } from '@/components/map/map-context' | ||
|
|
||
|
|
@@ -109,12 +110,14 @@ export default function RootLayout({ | |
| > | ||
| <MapContextProvider> | ||
| <MapLoadingProvider> | ||
| <Header /> | ||
| <ConditionalLottie /> | ||
| {children} | ||
| <HistorySidebar /> | ||
| <Footer /> | ||
| <Toaster /> | ||
| <TooltipProvider> | ||
| <Header /> | ||
| <ConditionalLottie /> | ||
| {children} | ||
| <HistorySidebar /> | ||
| <Footer /> | ||
| <Toaster /> | ||
| </TooltipProvider> | ||
|
Comment on lines
+113
to
+120
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
SuggestionConsider moving Example: <body>
<TooltipProvider>
{/* all existing providers/components */}
</TooltipProvider>
</body>This reduces the risk of tooltip context gaps when components render outside the current provider subtree. Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this refactor. |
||
| </MapLoadingProvider> | ||
| </MapContextProvider> | ||
| </ThemeProvider> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,11 @@ import { useUsageToggle } from './usage-toggle-context' | |
| import { useProfileToggle } from './profile-toggle-context' | ||
| import { useHistoryToggle } from './history-toggle-context' | ||
| import { useState, useEffect } from 'react' | ||
| import { | ||
| Tooltip, | ||
| TooltipContent, | ||
| TooltipTrigger | ||
| } from '@/components/ui/tooltip' | ||
|
|
||
| export const Header = () => { | ||
| const { toggleCalendar } = useCalendarToggle() | ||
|
|
@@ -52,15 +57,26 @@ export const Header = () => { | |
| </div> | ||
|
|
||
| <div className="absolute left-1 flex items-center"> | ||
| <Button variant="ghost" size="icon" onClick={toggleHistory} data-testid="logo-history-toggle"> | ||
| <Image | ||
| src="/images/logo.svg" | ||
| alt="Logo" | ||
| width={20} | ||
| height={20} | ||
| className="h-5 w-auto" | ||
| /> | ||
| </Button> | ||
| <Tooltip> | ||
| <TooltipTrigger asChild> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| onClick={toggleHistory} | ||
| data-testid="logo-history-toggle" | ||
| aria-label="Toggle history" | ||
| > | ||
|
Comment on lines
+62
to
+68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, locate the header component and read it
find . -name "header.tsx" -o -name "header.ts" | head -5Repository: QueueLab/QCX Length of output: 79 🏁 Script executed: # If found, read the file with line numbers, focusing on the relevant sections
wc -l components/header.tsxRepository: QueueLab/QCX Length of output: 81 🏁 Script executed: # Check what the hooks (useHistoryToggle, useCalendarToggle, useUsageToggle) export
rg -n "export.*useHistoryToggle|export.*useCalendarToggle|export.*useUsageToggle" --type ts --type tsx -A 5Repository: QueueLab/QCX Length of output: 83 🏁 Script executed: # Also search for hook definitions and what they return
rg -n "function useHistoryToggle|function useCalendarToggle|function useUsageToggle|const useHistoryToggle|const useCalendarToggle|const useUsageToggle" --type ts --type tsx -A 10Repository: QueueLab/QCX Length of output: 83 🏁 Script executed: cat -n components/header.tsxRepository: QueueLab/QCX Length of output: 5561 🏁 Script executed: # Search for hook definitions without type filtering
rg -n "useHistoryToggle|useCalendarToggle|useUsageToggle" -A 8Repository: QueueLab/QCX Length of output: 13070 🏁 Script executed: # Search for where these hooks are imported and used in header.tsx
rg -n "const.*useHistory|const.*useCalendar|const.*useUsage" -A 3Repository: QueueLab/QCX Length of output: 3986 🏁 Script executed: # Read the usage-toggle-context to see its interface
cat -n components/usage-toggle-context.tsxRepository: QueueLab/QCX Length of output: 1156 🏁 Script executed: # Read the history-toggle-context to see its interface
cat -n components/history-toggle-context.tsxRepository: QueueLab/QCX Length of output: 1231 🏁 Script executed: # Read the calendar-toggle-context to see its interface
cat -n components/calendar-toggle-context.tsxRepository: QueueLab/QCX Length of output: 1288 Toggle buttons are missing Buttons that open/close panels must communicate their current state to assistive technologies. Without All three toggle state values are available from their respective hooks and should be destructured and applied:
🤖 Prompt for AI Agents |
||
| <Image | ||
| src="/images/logo.svg" | ||
| alt="Logo" | ||
| width={20} | ||
| height={20} | ||
| className="h-5 w-auto" | ||
| /> | ||
| </Button> | ||
| </TooltipTrigger> | ||
| <TooltipContent side="bottom">Toggle history</TooltipContent> | ||
| </Tooltip> | ||
|
Comment on lines
+60
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logo button now has both an For purely decorative icons inside an already-labeled control, the icon/image should typically be hidden from assistive tech. SuggestionMake the logo image decorative within the button so the button’s accessible name is solely controlled by Options:
<Image src="/images/logo.svg" alt="" ... />
<Image ... alt="Logo" aria-hidden="true" />(Prefer |
||
| <h1 className="text-2xl font-poppins font-semibold text-primary"> | ||
| QCX | ||
| </h1> | ||
|
|
@@ -71,15 +87,36 @@ export const Header = () => { | |
|
|
||
| <MapToggle /> | ||
|
|
||
| <Button variant="ghost" size="icon" onClick={toggleCalendar} title="Open Calendar" data-testid="calendar-toggle"> | ||
| <CalendarDays className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> | ||
| <Tooltip> | ||
| <TooltipTrigger asChild> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| onClick={toggleCalendar} | ||
| data-testid="calendar-toggle" | ||
| aria-label="Open calendar" | ||
| > | ||
| <CalendarDays className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> | ||
| </TooltipTrigger> | ||
| <TooltipContent side="bottom">Open calendar</TooltipContent> | ||
| </Tooltip> | ||
|
|
||
| <div id="header-search-portal" className="contents" /> | ||
|
|
||
| <Button variant="ghost" size="icon" onClick={handleUsageToggle}> | ||
| <TentTree className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> | ||
| <Tooltip> | ||
| <TooltipTrigger asChild> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| onClick={handleUsageToggle} | ||
| aria-label="Open usage" | ||
| > | ||
|
Comment on lines
+109
to
+114
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Missing The logo-history button ( 🔧 Proposed fix- onClick={handleUsageToggle}
- aria-label="Open usage"
+ data-testid="usage-toggle"
+ onClick={handleUsageToggle}
+ aria-label="Open usage"Apply the same 🤖 Prompt for AI Agents |
||
| <TentTree className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> | ||
| </TooltipTrigger> | ||
| <TooltipContent side="bottom">Open usage</TooltipContent> | ||
| </Tooltip> | ||
|
|
||
| <ModeToggle /> | ||
|
|
||
|
|
@@ -88,10 +125,19 @@ export const Header = () => { | |
|
|
||
| {/* Mobile menu buttons */} | ||
| <div className="flex md:hidden gap-2"> | ||
|
|
||
| <Button variant="ghost" size="icon" onClick={handleUsageToggle}> | ||
| <TentTree className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> | ||
| <Tooltip> | ||
| <TooltipTrigger asChild> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| onClick={handleUsageToggle} | ||
| aria-label="Open usage" | ||
| > | ||
| <TentTree className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> | ||
| </TooltipTrigger> | ||
| <TooltipContent side="bottom">Open usage</TooltipContent> | ||
| </Tooltip> | ||
|
Comment on lines
+128
to
+140
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tooltip on mobile ( Radix UI's Consider whether this 🤖 Prompt for AI Agents |
||
| <ProfileToggle/> | ||
| </div> | ||
| </header> | ||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two
markdownlintwarnings flagged by static analysis.##heading on line 2 is not followed by a blank line; content starts immediately on line 3.#heading, not##.📝 Proposed fix
📝 Committable suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 2-2: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 2-2: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
🤖 Prompt for AI Agents