# Palette's Journal

## 2025-02-27 - Hardcoded tabIndex={-1} in Primitives
**Learning:** Found that UI primitives like `DeleteButton` had `tabIndex={-1}` hardcoded to prevent focus stealing in React Flow canvas, but this broke keyboard accessibility when used in standard UI lists.
**Action:** Default primitives to `tabIndex={0}` (accessible) and explicitly pass `tabIndex={-1}` only when using them inside canvas nodes.

## 2025-05-23 - Inconsistent Accessible Names in Primitives
**Learning:** `RefreshButton` was missing `aria-label` while other primitives had it, causing it to be invisible to screen readers (and Playwright `get_by_role` with name). Even if `Tooltip` is present, the interactive element must have an accessible name.
**Action:** Always verify `aria-label` on icon-only buttons, even if a Tooltip is used.

## 2026-02-27 - Hidden Focus Traps in State Buttons
**Learning:** `StateIconButton` (used for ThemeToggle, AgentMode) had hardcoded `tabIndex={-1}`, making critical global controls keyboard-inaccessible. This pattern of "canvas-first" components breaking standard UI accessibility persists.
**Action:** When auditing UI primitives, check if they are "dual-use" (canvas vs. panel) and ensure `tabIndex` is configurable, defaulting to `0`.
## 2024-06-18 - Missing ARIA Labels on Core UI Primitives
**Learning:** Many core icon-based UI primitives (like `CircularActionButton`, `ToolbarIconButton`, `DownloadButton`, `PlaybackButton`) in this application were missing `aria-label`s, rendering them inaccessible to screen readers despite having visual tooltips. The tooltips were not automatically functioning as accessible names. Furthermore, grouped buttons (like in `ActionButtonGroup`) lacked semantic grouping structure (`role="group"`).
**Action:** When creating or modifying custom icon-only components, always extract the string value from the `tooltip` prop (e.g., `typeof tooltip === 'string' ? tooltip : undefined`) to explicitly set the `aria-label` attribute on the underlying `IconButton` or `button` element. Use `role="group"` and `aria-label` for logical groupings of actions to provide proper context to screen readers.
## 2024-03-04 - ARIA Labels on Material-UI Switch Components
**Learning:** For Material UI `<Switch>` components, particularly those without wrapping `FormControlLabel` (like icon toggles), an `inputProps={{ "aria-label": "..." }}` must be explicitly provided for screen readers to recognize the toggle's purpose.
**Action:** When adding or auditing `<Switch>` components that toggle visual modes or act as standalone icons, always apply descriptive `inputProps` for accessibility.
## 2023-10-27 - Explicit tabIndex={0} on native buttons is a functional no-op
**Learning:** Adding `tabIndex={0}` to components that wrap native HTML buttons or MUI `IconButton` elements does not actively change or improve keyboard accessibility, as they are inherently focusable and included in the tab order by default. It fails the requirement to provide an "immediate, visible impact" on UX.
**Action:** Focus on semantic accessibility improvements, such as ensuring screen readers receive appropriate context (e.g., dynamically generating `aria-label` for stateful or count-based components like `NotificationBadge`), rather than redundant HTML attributes. When writing verification scripts for the `/layouttest` page, remember to write logic to switch to the correct tab category before trying to select elements.
## 2024-04-10 - Adding role="status" to Empty States
**Learning:** For dynamically rendered empty state components like `EmptyState`, screen readers may not announce the content when it appears, leaving users unaware of the state change.
**Action:** Always add `role="status"` and `aria-live="polite"` to empty states to ensure screen readers announce them appropriately.

## 2026-03-27 - Adding ARIA labels to ToolbarIconButton and StateIconButton with complex Tooltips
**Learning:** `StateIconButton` and `ToolbarIconButton` try to automatically extract an `aria-label` from their `tooltip` prop (`typeof tooltip === 'string' ? tooltip : undefined`). However, when the `tooltip` prop receives a ReactNode (like a formatted complex tooltip with a title and shortcut), the `aria-label` becomes `undefined`, leaving the icon button inaccessible to screen readers.
**Action:** When using `StateIconButton` or `ToolbarIconButton` with a ReactNode tooltip, always explicitly provide the `ariaLabel` prop with a descriptive string.
## 2026-03-27 - Adding ARIA labels to ToolbarIconButton with complex Tooltips
**Learning:** `ToolbarIconButton` extracts an `aria-label` from its `tooltip` prop automatically (`typeof tooltip === 'string' ? tooltip : undefined`). However, when the `tooltip` prop receives a ReactNode (like a formatted complex tooltip with a title and shortcut), the `aria-label` becomes `undefined`, leaving the icon button inaccessible to screen readers.
**Action:** When using `ToolbarIconButton` with a ReactNode tooltip, always explicitly provide the `ariaLabel` prop with a descriptive string. I've updated `ToolbarIconButton` to explicitly support the `ariaLabel` prop to fix this issue going forward.

## 2026-03-27 - Adding ARIA labels to CircularActionButton and DeleteButton with complex Tooltips
**Learning:** Similar to `ToolbarIconButton` and `StateIconButton`, `CircularActionButton` and `DeleteButton` try to automatically extract an `aria-label` from their `tooltip` prop. If the `tooltip` prop receives a ReactNode, the `aria-label` becomes `undefined` or falls back to generic text, leaving the icon button inaccessible to screen readers or lacking specific context.
**Action:** When using `CircularActionButton` or `DeleteButton` with a ReactNode tooltip, always explicitly provide the `ariaLabel` prop with a descriptive string. I've updated these components to explicitly support the `ariaLabel` prop.
## 2025-02-12 - Added missing `aria-label`s to `IconButton` components
**Learning:** Found that custom/complex components wrapped in MUI `IconButton` often drop context needed for screen readers if only icon nodes are provided as children, creating empty access labels for crucial UI actions.
**Action:** When creating action buttons consisting strictly of an icon, ensure to explicitly pass an `aria-label` attribute on the bounding `IconButton` component to preserve accessibility.
## 2025-05-30 - Missing ARIA Labels on Icon-only Submit Buttons
**Learning:** Icon-only submit buttons (like the send button in `PortalInput`) often omit `aria-label`s, rendering them inaccessible to screen readers. Relying solely on the visual icon to convey the button's purpose is a common pattern that breaks accessibility.
**Action:** When auditing or creating input components with icon-only submission buttons, always ensure an explicit `aria-label` is provided to describe the action (e.g., "Send message").
## 2024-06-25 - Using `LoadingSpinner` Primitive over Raw Material-UI
**Learning:** Found instances of raw Material-UI `CircularProgress` usage in components like `CircularActionButton`, `DialogActionButtons`, `DownloadButton`, `RefreshButton`, `RunWorkflowButton`, and `StateIconButton`. This usage goes against `STRATEGY.md` standardizing UI primitives.
**Action:** When working on UI components, use the explicit primitive `<LoadingSpinner inline />` over the raw `<CircularProgress>` to adhere to standardisation guidelines. Ensure proper test updates to reflect mock substitutions.
## 2025-05-30 - Added missing aria-labels to scattered IconButtons
**Learning:** Some custom UI interactions like NodeTestRow, DataframeRenderer, and ReplicateSchemaLoader were missing `aria-label` properties on their icon-only `IconButton` components, breaking accessibility for interactive elements, despite sometimes having `<Tooltip>` wrappers.
**Action:** Always add an explicit `aria-label` matching the interactive intent whenever rendering an icon-only `<IconButton>`.
## 2026-04-24 - Tooltips on disabled Material-UI IconButtons
**Learning:** By default, disabled HTML elements (like the `<IconButton disabled>`) do not fire mouse events (like `hover` or `mouseenter`). Because of this, any `<Tooltip>` wrapping the disabled button fails to appear, hiding important state context from the user.
**Action:** When wrapping a potentially `disabled` Material-UI component (like an `<IconButton disabled>`) inside a `<Tooltip>`, wrap the disabled component in a `<span style={{ display: 'inline-flex' }}>` tag. The `inline-flex` display preserves the intended component layout and alignment while capturing the pointer events so the tooltip can appear.
## 2026-05-09 - Dynamic aria-labels in Dialogs/Drawers
**Learning:** Found that generic UI containers like `DrawerPanel` used hardcoded `aria-label="Close drawer"` on their close buttons, limiting context for screen reader users when multiple drawers exist.
**Action:** When creating or updating generic container components with close buttons, use dynamic `aria-label`s based on the container's title (e.g., `aria-label={title ? \`Close ${title} drawer\` : "Close drawer"}`) to provide specific context.

## 2026-06-25 - ARIA Labels on Icon Buttons in SketchLayersPanel
**Learning:** Found that numerous native Material-UI `<IconButton>` instances across the heavily-used `SketchLayersPanel` (e.g., duplicate, clear, merge, delete layer) lacked `aria-label`s, rendering them inaccessible to screen readers despite having visual `<Tooltip>` wrappers.
**Action:** Always ensure that `IconButton` instances, especially within dense panels like `SketchLayersPanel`, have an explicit `aria-label` that matches their tooltip text to guarantee screen reader compatibility. Do not assume the tooltip alone provides an accessible name.
## 2025-02-28 - Missing ARIA Labels on Text/Image Layer Generation Icons
**Learning:** Found that some newer `IconButton` tools inside `SketchLayersPanel.tsx` (Add Text-to-Image Layer, Add Image-to-Image Layer) were missing explicit `aria-label` attributes despite having Material-UI `Tooltip` components. Because tooltips alone do not reliably announce inner action intents to screen readers on interactable buttons, explicit ARIA labels are necessary.
**Action:** Always add an explicit `aria-label` property mirroring the tooltip `title` onto standard Material-UI `IconButton` elements, particularly those responsible for core functionalities like generating specialized layer types.
## 2026-05-14 - Adding ARIA labels to custom editor modal buttons
**Learning:** Icon-only UI buttons inside custom modals, such as `TextEditorModal`, `DataframeEditorModal`, and `SnippetSidebar`, were found to lack `aria-label` attributes. While they had visual tooltips, screen readers and automation tools (like Playwright's `get_by_role`) could not identify their purpose.
**Action:** Always provide explicit `aria-label` properties on interactive elements that rely solely on icons to convey their action, ensuring the label matches the visual tooltip text and appropriately reflects dynamic states.
