-
Notifications
You must be signed in to change notification settings - Fork 18
Description
Context
The current design system uses Stitches which was sunset in 2023 and is no longer maintained. Stitches defines CSS-side breakpoints (@bp1–@bp4) but has no JS-side media query hooks, which forces us to hardcode pixel values in JS when using useWindowSize().
This has already caused bugs — see #578 where a hardcoded 1020px was misaligned with the @bp3 (1200px) CSS breakpoint, creating a dead zone where buttons were visible but non-functional.
Goal
When migrating to Radix UI + Tailwind CSS, centralize breakpoint logic so CSS and JS always use the same source of truth.
Recommended approach (Tailwind v4)
Tailwind v4 generates CSS variables for all theme values, including breakpoints. The official recommendation is to read them from CSS rather than maintaining a separate JS config:
// Read breakpoint values directly from CSS variables at runtime
const styles = getComputedStyle(document.documentElement);
const lgBreakpoint = styles.getPropertyValue("--breakpoint-lg"); // e.g. "1200px"This replaces the v3 resolveConfig() approach (which was removed in v4 to reduce bundle size).
Custom hook example
function useBreakpoint(breakpoint: string): boolean {
const value = getComputedStyle(document.documentElement)
.getPropertyValue(`--breakpoint-${breakpoint}`);
const { width } = useWindowSize();
return width >= parseInt(value, 10);
}
// Usage
const isDesktop = useBreakpoint("lg");Tailwind theme config
Define breakpoints in CSS (Tailwind v4 style):
/* app.css */
@theme {
--breakpoint-sm: 520px; /* current @bp1 */
--breakpoint-md: 900px; /* current @bp2 */
--breakpoint-lg: 1200px; /* current @bp3 */
--breakpoint-xl: 1800px; /* current @bp4 */
}These are then available both in Tailwind classes (lg:flex) and in JS via getComputedStyle.
Locations currently using hardcoded breakpoints
| File | Current usage | What to update |
|---|---|---|
components/BottomDrawer/index.tsx |
width < 1200 |
!isDesktop or width < lg |
layouts/account.tsx |
width >= 1200 |
isDesktop or width >= lg |
layouts/main.tsx |
width >= 1200 / width < 1200 |
isDesktop / !isDesktop |
components/DelegatingWidget/Input.tsx |
width >= 1200 |
isDesktop |
pages/voting/[poll].tsx |
width > 1200 |
isDesktop |
pages/treasury/[proposal].tsx |
width >= 768 (isDesktop) |
Review — 768 doesn't match any current breakpoint |
Why move away from Stitches
- Unmaintained — no updates since 2023, open issues/PRs unaddressed
- No SSR streaming support — incompatible with React Server Components and Next.js App Router
- No JS breakpoint hooks — leads to hardcoded pixel values diverging from CSS
- Ecosystem momentum — Tailwind has broad tooling support, better DX, and active maintenance