Skip to content

feat(web): Add high-contrast mode setting#1284

Open
alacritythief wants to merge 2 commits intopingdotgg:mainfrom
alacritythief:high-contrast
Open

feat(web): Add high-contrast mode setting#1284
alacritythief wants to merge 2 commits intopingdotgg:mainfrom
alacritythief:high-contrast

Conversation

@alacritythief
Copy link

@alacritythief alacritythief commented Mar 21, 2026

Addresses & Fixes Related Issues

Addresses #254, #1279

Fixes #233, Fixes #400

What Changed

Added an opt-in High contrast mode setting to improve readability in both light and dark themes without changing the default appearance when the setting is off.

This includes:

  • adding highContrastMode to the existing app settings schema and persistence flow
  • exposing the toggle in Settings > Appearance
  • applying a root high-contrast class when the setting is enabled
  • adding CSS overrides under that class to strengthen muted/low-opacity text that was failing contrast checks
  • adding CSS overrides for non-text elements like borders

Why getLocalStorageItem is used

getLocalStorageItem is used so high contrast mode can be applied immediately at startup, before React renders.

That startup read is needed to avoid a flash where the app initially renders in normal contrast and only switches to high contrast after the app mounts. This mirrors the existing theme behavior, where theme classes are also applied early to avoid visual flicker.

The setting is still stored the same way as the rest of the app settings:

  • in the shared AppSettingsSchema
  • under the same t3code:app-settings:v1 local storage entry
  • updated via useAppSettings().updateSettings(...)

The only special handling is the early synchronous read so the root class can be applied before first paint.

Why

The app had multiple contrast issues in both dark and light mode, mainly from:

  • muted text being too weak on some surfaces
  • repeated use of low-opacity text-muted-foreground/* utilities
  • secondary metadata, helper text, empty states, and work-log labels becoming hard to read

The high contrast colors were chosen to bring these muted/read-secondary states closer to WCAG AA expectations for normal text contrast, instead of relying on visually subtle opacity reductions that were falling below accessible contrast thresholds. The goal here was not to redesign the palette, but to keep the existing visual language and raise the contrast of the specific text treatments that were failing.

Rather than changing the default theme for everyone, this PR adds a focused accessibility improvement that users can opt into when they want stronger readability.

Screenshots

High Contrast setting location
image

High Contrast togged ON
image

Dark mode with high contrast OFF
image

Dark mode with high contrast ON
image

Light mode with high contrast OFF
image

Light mode with with high contrast ON
image

Checklist

  • Added a persisted highContrastMode app setting
  • Kept the default color system unchanged when the setting is off
  • Applied high contrast styling through an opt-in root class
  • Placed the toggle in Settings > Appearance
  • Covered both light mode and dark mode contrast issues
  • Ran bun fmt
  • Ran bun lint
  • Ran bun typecheck
  • This change is as small as I can make it to be and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes

Note

Add high-contrast mode setting to the web app

  • Adds a highContrastMode boolean to AppSettingsSchema (default false) and persists it in localStorage.
  • Adds applyHighContrastMode() in appSettings.ts which toggles a high-contrast class on <html>, controlling CSS variables for muted text, borders, and inputs in both light and dark themes.
  • Applies the stored preference at startup in main.tsx before React renders, preventing a flash of unstyled content.
  • Exposes a Switch control in _chat.settings.tsx so users can toggle high-contrast mode and restore the default from the settings page.

Macroscope summarized 7255b26.

- Persist and apply a high-contrast class at startup and in the root route
- Add a settings toggle and restore control
- Boost muted text contrast in the UI
@coderabbitai
Copy link

coderabbitai bot commented Mar 21, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4058e014-d9cb-40c4-bd56-e079b0ef5648

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can generate a title for your PR based on the changes with custom instructions.

Set the reviews.auto_title_instructions setting to generate a title for your PR based on the changes in the PR with custom instructions.

@github-actions github-actions bot added size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Mar 21, 2026
@alacritythief alacritythief changed the title Add high-contrast mode setting feat(web) Add high-contrast mode setting Mar 21, 2026
@alacritythief alacritythief changed the title feat(web) Add high-contrast mode setting feat(web): Add high-contrast mode setting Mar 21, 2026
This was referenced Mar 22, 2026
@alacritythief
Copy link
Author

alacritythief commented Mar 22, 2026

Updated the PR description with related issues that are addressed and fixed with this PR and added comparison screenshots for tool calls.

@lukstafi
Copy link

lukstafi commented Mar 22, 2026

I prefer to change the backgrounds while keeping fonts as is. Vibe-coded: 98267d8
Note: this makes almost no difference for the light mode, but improves significantly the dark mode for me.

@github-actions github-actions bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Mar 22, 2026
@alacritythief
Copy link
Author

I prefer to change the backgrounds while keeping fonts as is. Vibe-coded: 98267d8 Note: this makes almost no difference for the light mode, but improves significantly the dark mode for me.

@lukstafi Thanks for the suggestion. I experimented with that and avoided it because I wanted to make a more comprehensive accessibility pass that follows WCAG 2.2 AA standards and proper contrast ratios in both modes. Pure black and white backgrounds can cause halation/readability issues. Your commit however did make me realize I should correct the non-text elements like borders too, so I updated my PR and screenshots to with that change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hard to read text Unmatched Contrast Levels

2 participants