MacOS menubar app to check color contrast
  • Swift 56.4%
  • HTML 21.3%
  • CSS 12.7%
  • JavaScript 8.8%
  • Python 0.8%
Find a file
2026-09-28 10:58:27 -04:00
Chromatic You can now choose to start Chromatic at login; fixes duplicate instances running over top of each other 2026-09-28 10:58:27 -04:00
Chromatic.xcodeproj You can now choose to start Chromatic at login; fixes duplicate instances running over top of each other 2026-09-28 10:58:27 -04:00
Configuration You can now choose to start Chromatic at login; fixes duplicate instances running over top of each other 2026-09-28 10:58:27 -04:00
Design Adds help content and a few screenshots; fixes color input in mini mode so that triple click now opens the picker 2026-09-21 12:21:09 -04:00
Public You can now choose to start Chromatic at login; fixes duplicate instances running over top of each other 2026-09-28 10:58:27 -04:00
Tests You can now choose to start Chromatic at login; fixes duplicate instances running over top of each other 2026-09-28 10:58:27 -04:00
Tools/Screenshots Fixes warning on deprecated call 2026-09-21 12:25:20 -04:00
.gitignore Working draft of menubar app! Window matchecs design with full color picking, ratio analysis, preview, and some quick fixes to meet various WCAG levels 2026-09-18 07:46:26 -04:00
README.md Working draft of menubar app! Window matchecs design with full color picking, ratio analysis, preview, and some quick fixes to meet various WCAG levels 2026-09-18 07:46:26 -04:00

Chromatic

A native macOS menubar utility to check color contrast and WCAG compliance, built from scratch with SwiftUI and AppKit.

Build the project

  • Xcode 26.6 (validated), macOS 26 or later.
  • Open Chromatic.xcodeproj, select the shared Chromatic scheme and My Mac, then Run.
  • Choose your signing team in Signing & Capabilities if Xcode requests one. The bundle identifier is currently the placeholder com.example.Chromatic; replace it before distribution.
  • The half-filled circle appears in the menu bar. There is intentionally no Dock icon (LSUIElement). Click the menu-bar icon to toggle the anchored popover. Close it with its close button or Escape while the popover has focus. Quit from the panel or press Command-Q while it is active.

The color editors accept 3- or 6-digit hex values with an optional #. Six-digit values update live; press Return to apply shorthand. The weather card is sample content. AA/AAA results use the unrounded WCAG ratio; the large header shows one decimal. The gear menu offers Copy Contrast Results and Quit.

Permissions

Neither Accessibility nor Screen Recording permission is required for this sampling flow. The system owns the interactive sampler and returns a selected color (or nil on cancellation). The app does not capture screenshots, inspect other apps, install event taps, or request broad access.

The only explicit entitlement is com.apple.security.app-sandbox. No privacy permission prompt, screen recording preflight, or Accessibility request should be added for NSColorSampler.

Apple documents the permission distinction in What’s New in AppKit for macOS (WWDC19). See also NSColorSampler and NSPopover.Behavior.applicationDefined.

Validation

Debug and Release builds can be checked without a developer account using local ad-hoc signing:

xcodebuild -project Chromatic.xcodeproj -scheme Chromatic \
  -configuration Debug -derivedDataPath /tmp/Chromatic-build \
  CODE_SIGN_IDENTITY=- CODE_SIGNING_ALLOWED=YES build

xcodebuild -project Chromatic.xcodeproj -scheme Chromatic \
  -configuration Release -derivedDataPath /tmp/Chromatic-build \
  CODE_SIGN_IDENTITY=- CODE_SIGNING_ALLOWED=YES build

Ad-hoc signing is only for local validation; Xcode disables Hardened Runtime for these builds. Distribution needs a real signing identity and notarization or App Store distribution.

Manual acceptance checks (require an interactive Mac session):

  1. Run the app and open its menu-bar panel; confirm there is no Dock icon.
  2. Open each native color well and select a color.
  3. Use each eyedropper to sample from another app or the desktop; verify the panel stays visible and the appropriate swatch changes.
  4. Start sampling and press Escape; verify the old color and panel remain and sampling can be started again.
  5. Switch to another app and confirm the panel remains visible. Return focus to the panel and press Escape to dismiss it. Reopen it, swap colors, and confirm selections survive dismissal.
  6. Verify the popover close button and menu-bar icon both dismiss it; reopen after each. Check anchoring near screen edges and opening from another display/Space.
  7. Check light/dark appearance, keyboard navigation, and VoiceOver labels.
  8. Confirm the sampling flow works without granting Accessibility or Screen Recording access.
  9. Quit from the panel.
  10. Edit/paste hex values, including #abc, 005E98, invalid values, and incomplete drafts; verify invalid input never replaces the active color. Test swapping while a field has focus.
  11. Compare black/white (21:1), identical colors (1:1), and #777777 on white (fails AA regular despite rounding close to 4.5).
  12. Copy results from the gear menu and check the clipboard against the displayed colors and conformance.

Run the standalone calculation and parsing checks (no dependencies or signing required):

xcrun swiftc -swift-version 6 Chromatic/ContrastMetrics.swift Tests/ContrastChecks.swift \
  -o /tmp/Chromatic-contrast-checks
/tmp/Chromatic-contrast-checks

These check luminance reference values, swap symmetry, parsing, and both sides of all WCAG thresholds. Build/math validation does not replace interactive checks. Light/dark Xcode previews are provided in SamplingView.swift.