Repository navigation
refactor(frontend): Replace Tailwind with StyleX - #408
Conversation
Restore the former input outline rule through StyleX in the tag editor and filters. The migration omitted their focus:outline-none declarations. Browser comparisons at 1280px and 850px confirm that dropdown geometry and scroll match Tailwind. All 193 frontend tests and applicable pre-commit and pre-push checks pass.
Replace the partial reset with current upstream Preflight in the reset layer. Expand its font helpers into standard CSS and distribute the MIT notice with the frontend assets. Remove the four inline input outline overrides to restore native browser focus. Verify upstream declaration parity, built CSS, dropdown geometry, calendars, forms, and all 193 frontend tests.
Restore the StyleX equivalent of focus:outline-none on the four inline dropdown inputs. Preflight remains the shared reset and other controls keep native focus. Browser checks fail before and pass after the change, with unchanged geometry and scrolling. All 193 frontend tests and required checks pass.
Compose dropdownInputStyles.focus in the tag editor and filters instead of defining the same focus rule in four places. Production CSS remains identical. All four inputs pass browser checks, and all 193 frontend tests and required hooks pass.
Suppress focus outlines for all inputs through the reset layer. Remove the shared dropdown helper so inputs receive the default automatically. Verified all five searchable dropdowns and a regular form input in the browser. Selects, textareas, and buttons retain native focus. All 193 frontend tests, lint, formatting, the production build, and applicable pre-commit and pre-push checks pass.
Wrap the incident list and availability error descriptions in paragraphs so their text, help link, and punctuation stay together within the flex layout. Verified both error screens in the browser and ran all 193 frontend tests and required checks.
Replace fixed neutral border colors across shared controls and dropdowns with border.secondary so borders follow the Scraps light and dark themes. Verified representative controls in the browser and both token values in production CSS. Existing focus behavior is unchanged. All 193 frontend tests and required checks pass.
Preserve the incoming branded Statuspage timeline icon and dark-mode inversion through StyleX. Retain the newer feature-branch input focus and downtime changes. All 194 frontend tests, type checking, lint, formatting, the production build, and required pre-commit checks pass. Affected backend database tests could not initialize because local PostgreSQL is unavailable.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ae49ece. Configure here.
|
|
||
| const handleKeyDown = (event: KeyboardEvent) => { | ||
| // Enter to save (only for single-line, or Ctrl/Cmd+Enter for multiline) | ||
| if (event.key === 'Enter') { | ||
| if (!multiline || event.ctrlKey || event.metaKey) { | ||
| event.preventDefault(); |
There was a problem hiding this comment.
Global Enter handler saves while other controls are focused
While editing, the document-level Enter listener saves without checking which element is focused. Pressing Enter on Cancel can therefore save the draft instead of cancelling; repeated Enter events can also invoke onSave concurrently because save() has no isSaving guard. Handle Enter on the editor input and prevent duplicate saves while one is pending.
Evidence
- While editing,
EditableTextFieldregisters a document-levelkeydownlistener that callssave()for Enter in single-line mode, or Ctrl/Cmd+Enter in multiline mode. - The listener does not check
event.target; it prevents the default and callssave()even when focus is on Cancel, so keyboard activation of Cancel can be suppressed. save()setsisSavingbut does not check it before callingonSave, so repeated qualifying keydowns can start concurrent saves; the existing tests cover clicking Cancel and Save, but not these keyboard cases.
Identified by Warden · find-bugs · HCC-GG4
There was a problem hiding this comment.
These issues existed before the migration, instead i filed issues for them to be tackled at a later date:

Times are a changing, and who doesn't love a good ol'refactor. The goal of this PR is to migrate away from Tailwind, and instead over to StyleX. The reason for this is that we live in a world of agents now, and constant validation is key to ensuring durable, and good code. StyleX provides this via type safe styles unlike those of Tailwind, which at the end of the day are just strings.
🤖 generated description below:
Why
Replace Tailwind throughout the frontend with StyleX. Shared components accept compiled styles through typed
styleprops, so callers can compose overrides without class strings or raw CSS objects.What changed
cn.tokens.stylex.tsfrom Scraps colors, spacing, radii, and typography. Store direct values with dark-mode media overrides. Removescraps-theme.cssand the intermediate variable aliases.Scope
The change covers frontend application styling. The backend and API contracts are unchanged. No demo page remains.
Global CSS retains font faces and the latest Tailwind Preflight, adapted as standalone CSS in the reset layer. All native inputs suppress focus outlines through a global reset rule. Buttons, links, selects, and textareas retain native focus. Calendar adapters use generated classes internally, and Radix manages its runtime positioning.
Tradeoffs
Scraps exports ordinary JavaScript objects that the StyleX compiler cannot import directly as tokens. A generator converts those values into a StyleX module and checks the committed output during lint. StyleX emits the CSS declarations. Preflight uses standard CSS font defaults in place of its Tailwind compiler helpers. Its MIT notice ships with the production assets.
Blast radius
Every frontend screen uses the new styling path. Review the global reset, calendar adapters, dynamic measurements, and conditional style precedence closely.
Verification