Files
supabase/.coderabbit.yaml
Miranda Limonczenko 8c745017fb chore(a11y): have CodeRabbit flag live regions, keyboard, motion, and alt text (#49216)
Closes FE-3811

## Problem

CodeRabbit reviews UI PRs without prompting on accessibility gaps
axe-core cannot judge: live regions, keyboard and hover, reduced motion,
alt quality, focus visibility, color-only state, and vague link names.

## Solution

- Add a path_instruction on `{apps,packages}/**/*.{tsx,jsx,css,mdx}`.
- Keep comments advisory. Skip tests, generated files, Radix/shadcn from
`ui`, and mechanical axe findings.
- Cover live-region lifecycle, pointer-only and hover-only UI, reduced
motion, alt quality including a two-sentence length heuristic, focus
rings, color-only state, and generic link names.

## Manual testing

1. After merge, open a PR that touches a UI or MDX file under `apps/` or
`packages/`.
2. Confirm CodeRabbit comments on at least one of: an unannounced status
change, a live region created with its message, a pointer-only or
hover-only control, animation without reduced motion, generic or
redundant or long alt, `outline-none` without a focus-visible
replacement, color-only status, or a "learn more" link that does not
name its destination.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Accessibility**
* Expanded accessibility review coverage for interface content and
styling.
* Reviews now identify missing focus indicators, color-only status or
selection cues, and unclear link labels.
* Continued checks cover state announcements, pointer-only interactions,
reduced-motion support, and alternative text quality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 07:29:37 -07:00

141 lines
8.4 KiB
YAML

# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
# Don't inherit organization-level settings (they're tuned for other repos);
# this config is self-contained and unset values use CodeRabbit defaults.
inheritance: false
# Enrich linked issues with related code and potential solutions during review.
issue_enrichment:
auto_enrich:
enabled: true
reviews:
# Skip machine-generated / vendored files (mirrors .prettierignore). Keeps
# reviews focused on hand-written code and preserves rate-limit budget on
# large codegen diffs.
path_filters:
- '!pnpm-lock.yaml'
- '!packages/api-types/types/**' # generated API types (api.d.ts, platform.d.ts)
- '!supabase/functions/common/database-types.ts' # generated by `pnpm generate:types`
- '!**/routeTree.gen.ts' # TanStack Router generated
- '!**/__generated__/**'
- '!apps/docs/features/docs/generated/**'
- '!apps/www/.generated/**'
- '!apps/design-system/__registry__/**'
- '!apps/ui-library/__registry__/**'
- '!apps/ui-library/public/r/**' # registry output
- '!packages/icons/__registry__/**'
- '!packages/icons/src/icons/**' # generated icon components
# Targeted, path-scoped review guidance, version-controlled alongside the code.
path_instructions:
- path: 'packages/common/telemetry-constants.ts'
instructions: |
Strictly enforce event naming: [object]_[verb] in snake_case. Only approved
verbs: opened, clicked, submitted, created, removed, updated, retrieved,
intended, evaluated, added, enabled, disabled, copied, exposed, failed,
converted. Properties must be camelCase for new events (match existing
convention when adding to existing events). Flag any usage of
useSendEventMutation. Verify @group Events and @source JSDoc tags are
accurate. Check that new interfaces are added to the TelemetryEvent union type.
- path: 'apps/studio/components/**/!(*.test).tsx' # production components only, not tests
instructions: |
Only suggest adding PostHog event tracking (via useTrack from
lib/telemetry/track, [object]_[verb] snake_case) when a new user-facing
interaction is growth-relevant: e.g. first-use of a feature, onboarding steps,
project/org creation, upgrade/billing actions, enabling or disabling a product
feature, or any action that signals activation or retention. Do not suggest
tracking for: passive views, page loads, UI-only state changes (e.g. expanding
a panel, switching tabs in a settings page), developer/internal tooling
interactions, or interactions clearly unrelated to product adoption.
- path: 'apps/studio/pages/**'
instructions: |
Studio is mid-migration from the Next.js pages router (apps/studio/pages/**)
to TanStack Start (apps/studio/routes/**). Both runtimes ship side-by-side, so
every URL served from pages/** has a mirror in routes/**. See
apps/studio/TANSTACK_MIGRATION.md for the full route map and strategy.
Leave a comment reminding the author to check whether this change needs to be
mirrored into the corresponding apps/studio/routes/** file so the two builds
don't silently drift:
- Most route files re-export the page's default export (Path A), so pure
page-body edits propagate automatically — no mirror needed.
- A mirror IS needed when the change touches something the route file
duplicates rather than imports: getLayout / layout wrapping, page title or
other props the route encodes as staticData, withAuth / auth gating, or the
route/redirect path itself.
- A brand-new page under pages/** needs a matching new route under routes/**
(and a checklist entry in apps/studio/TANSTACK_MIGRATION.md).
- Do NOT suggest deleting the pages/** file — the Next file stays load-bearing
for both runtimes until the final cleanup pass (tracked in FE-3106).
Keep this a reminder to verify, not a hard blocker: if no mirror is required,
say so briefly rather than forcing a change.
- path: '{apps,packages}/**/*.{tsx,jsx,css,mdx}'
instructions: |
When reviewing UI changes, flag these accessibility gaps. Comments are
advisory. One comment per gap. Skip test files (*.test.*, *.spec.*) and
generated files. Skip Radix/shadcn primitives imported from ui for all
checks below. Do not flag issues axe-core already catches mechanically,
such as a missing alt attribute, an empty button or link name, or
invalid ARIA.
- State changes: if sighted users can see a status change (toast,
loading/empty swap, copy confirmation, async result) and nothing
announces it, suggest aria-live="polite" or role="status". Reserve
role="alert" for urgent errors or warnings. Skip if a live region,
Radix Toast, or Sonner is already there, or if the change is
decoration only. If a live region is created in the same conditional
as its message, flag that: the region must already exist in the DOM,
then receive the update, or screen readers often announce nothing.
- Mouse interaction: flag pointer-only handlers on a non-interactive
element (div, span, or similar) with no keyboard equivalent. The
listed handlers are illustrative: onClick, onMouseEnter,
onDoubleClick, onContextMenu, onPointerDown, onPointerUp,
onTouchStart, onTouchEnd, and equivalents. Also flag hover-only UI
(content revealed with onMouseEnter or CSS :hover) that has no focus
or keyboard path.
- Animation: flag animate-*, keyframes, or JS motion with no
reduced-motion treatment. Prefer Tailwind motion-reduce: /
motion-safe:, or matchMedia('(prefers-reduced-motion: reduce)').
packages/config/css/utilities.css only zeroes out .shimmer under
reduced motion, not all animation.
- Alt text: flag generic values such as Image, Icon, Photo, Picture, or
the filename. Flag alt that starts with "image of" or "picture of".
If adjacent visible text already names the image (blog thumbnail next
to its title, icon next to its label), flag it as redundant and
recommend alt="" plus aria-hidden on the image. For a decorative SVG
next to visible text, recommend aria-hidden on the SVG. If alt is
longer than about two sentences, suggest moving the extra into a
caption, adjacent text, or aria-describedby. Do not treat a character
count as a hard fail.
- Focus visibility: flag outline-none, outline-hidden, outline: none,
outline: 0, or equivalent :focus resets that are not paired with a
focus-visible ring or outline, or with the focus-ring or focus-inset
utility.
- Color-only state: flag status, validation, or selection that is
conveyed only by color. Suggest a text label, icon, or sr-only text
in addition.
- Link purpose: flag an accessible name that is only "click here",
"read more", or "learn more" when it does not describe the
destination. Skip if aria-label or wrapping context already names
where the link goes.
# Applies our internal engineering skills (.claude/skills/) as CodeRabbit review
# guidelines. The skills are the single source of truth — they are consumed
# directly, with no copy of their content elsewhere.
#
# `applyTo` decouples where a guideline file lives from the code it governs.
# Without it, CodeRabbit scopes a guideline file to its own directory and below;
# our skills live in .claude/skills/, which contains no code, so they would never
# reach apps/studio. `applyTo` points them at the right paths instead.
knowledge_base:
code_guidelines:
filePatterns:
# Studio code conventions — React/TS, UI patterns, composition, data fetching, errors
- files: '.claude/skills/{studio-best-practices,studio-ui-patterns,vercel-composition-patterns,studio-queries,studio-error-handling,react-hook-form}/SKILL.md'
applyTo: 'apps/studio/**/*.{ts,tsx}'
# Studio unit / component test conventions
- files: '.claude/skills/{studio-testing,studio-mock-api-tests}/SKILL.md'
applyTo: 'apps/studio/**/*.test.{ts,tsx}'
# Studio end-to-end (Playwright) test conventions
- files: '.claude/skills/studio-e2e-tests/SKILL.md'
applyTo: 'e2e/studio/**/*.spec.ts'