-
Notifications
You must be signed in to change notification settings - Fork 373
Description
Description
The @stylexjs/sort-keys ESLint rule sorts style properties alphabetically, including media query keys inside responsive objects. This conflicts with CSS cascade requirements for max-width media queries, where larger breakpoints must appear before smaller ones in source order.
Even when following all documented best practices:
- Using
enableMediaQueryOrder: true(as recommended in v0.15.0+) - Using inline string literals for media queries (required for Vite compatibility)
- Ordering breakpoints correctly for max-width cascade (larger first)
Running eslint --fix will re-sort the media queries alphabetically, breaking the cascade.
Reproduction
Setup (following best practices)
vite.config.js:
styleXUnplugin.vite({
enableMediaQueryOrder: true, // Recommended in v0.15.0+
})eslint.config.mjs:
{
plugins: { "@stylexjs": stylexPlugin },
rules: {
"@stylexjs/sort-keys": "warn", // Recommended StyleX ESLint rule
},
}The Problem
Correct code (larger breakpoint first for max-width cascade):
const styles = stylex.create({
container: {
padding: {
default: "2rem",
"@media (max-width: 768px)": "1.5rem", // tablet
"@media (max-width: 640px)": "1rem", // mobile (overrides tablet)
},
},
});After running eslint --fix:
const styles = stylex.create({
container: {
padding: {
default: "2rem",
"@media (max-width: 640px)": "1rem", // now first (alphabetically)
"@media (max-width: 768px)": "1.5rem", // now last - WINS on mobile!
},
},
});Why This Breaks
With enableMediaQueryOrder: true, StyleX makes "later source order wins." After ESLint sorts:
640pxappears first in source768pxappears last in source → takes precedence- On a 500px viewport, BOTH queries match, but
768pxwins because it's later - Result: Mobile devices get
1.5reminstead of1rem
Expected Behavior
The @stylexjs/sort-keys rule should either:
- Skip sorting inside objects containing media query keys - Detect
@mediakeys and preserve author order - Sort media queries by specificity - For
max-width, sort descending (larger first); formin-width, sort ascending (smaller first) - Provide a configuration option - Allow disabling sort-keys for media query objects
Current Workaround
We must add ESLint disable blocks around every responsive property:
const styles = stylex.create({
container: {
/* eslint-disable @stylexjs/sort-keys -- max-width cascade: larger breakpoints first */
padding: {
default: "2rem",
"@media (max-width: 768px)": "1.5rem",
"@media (max-width: 640px)": "1rem",
},
/* eslint-enable @stylexjs/sort-keys */
},
});This is tedious and error-prone, especially since the ESLint warning says:
StyleX property key "@media (max-width: 640px)" should be above "@media (max-width: 768px)"
This message actively encourages the wrong order for max-width queries.
Environment
@stylexjs/stylex: 0.10.1@stylexjs/eslint-plugin: 0.10.1@stylexjs/unplugin: 0.6.0- Vite: 6.0.5
- Node: 22.x
Related Issues
- autofix for @stylexjs/sort-keys #415 - autofix for @stylexjs/sort-keys
- Detect intended Media query boundaries by order. #517 - Detect intended Media query boundaries by order
- Set CSS rule priority based on media query break points #82 - Set CSS rule priority based on media query break points