StyleX
SkillDev toolsStyleX styling for this codebase. Use when writing or editing any style, adding or restyling a component, touching stylex.create/props/defineVars/createTheme, changing the babel or postcss config, or converting Tailwind classes, cn(), or cva() variants to StyleX.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the StyleX skill
What this skill tells your AI
The instructions your AI receives, as published by joeymckenzie/joeymckenzie.tech in .claude/skills/stylex/SKILL.md and read by ahel’s review.
StyleX is a build-time compiler. Styles are extracted to atomic CSS at compile time, so a style the compiler cannot see statically does not exist at runtime — and fails silently, rendering an unstyled element rather than an error. Every rule in the references follows from that, and it is why the checks at the bottom of this file are build checks.
Route
Read the reference for your branch before writing code. Do not write StyleX from memory: the API is close enough to CSS-in-JS you have seen to feel familiar and different enough to be wrong.
| Doing | Read |
|---|---|
| writing or editing styles, in any file | references/authoring.md |
converting a Tailwind/shadcn/cva component, or planning the migration | references/migration.md, then authoring.md |
| installing StyleX, or changing babel/postcss/build config | references/installation.md, then This repo below |
authoring.md and installation.md are the upstream StyleX docs, vendored
verbatim from https://stylexjs.com/docs/llm-resources. Re-download them to
update; a hand edit is lost on the next sync, so repo-specific facts go in this
file or in migration.md.
This repo
Where installation.md's generic Next.js advice is wrong here. The build is
already configured — read babel.config.js and postcss.config.mjs, which
carry the same reasoning at the point of use. This is the summary.
- Babel config carries the StyleX plugin only, plus
parserOpts. This is Next 16 on Turbopack, which auto-detects a Babel config file and runs it while SWC still handles Next's internal transforms and downleveling (node_modules/next/dist/docs/01-app/03-api-reference/08-turbopack.md).installation.md'spresets: ['next/babel']is webpack-era advice; under Turbopack it re-runs work SWC has already done. But dropping the preset also drops Babel's ability to parse TS and JSX, and it fails on the firstimport type— so the config setsparserOpts(typescripteverywhere,jsxscoped to.tsxviaoverrides) to restore syntax without adding a transform. - A Babel pass in front of Turbopack breaks
@/aliases in dynamic imports. A file that has been through a loader no longer gets the alias applied when Turbopack resolves a template-literalimport()into a context module:app/blog/[slug]/page.tsxhad to switch to a relative specifier. Static imports are unaffected. If a build fails withModule not found: Can't resolve '@/… ' <dynamic> '…', this is why. - The PostCSS plugin must not be handed the Babel plugin list. The StyleX
docs import
babel.config.jsintopostcss.config.jsand passplugins: babelConfig.pluginsthrough. Turbopack serialises the PostCSS config across its Rust boundary and rewrites every project-root path in it to the literal string/ROOT/, so the plugin arrives withaliases: {"@/*": ["/ROOT/*"]}and cannot resolve@/app/tokens.stylex--Could not resolve the path to the imported file, reported againstapp/globals.css. Omittingpluginslets Babel loadbabel.config.jsitself inside the worker, where__dirnameis real. - Babel's
ignoredoes nothing. Next's loader hands Babel a placeholder filename when it resolves the config, so path-basedignore/onlyentries never match. Do not reach for them to scope what Babel sees. postcss.config.mjsis ESM.installation.mdwrites CommonJS (require/module.exports). Useimport/export defaultand keep the.mjsextension.useCSSLayersstaysfalse. Tailwind is gone, butapp/globals.cssstill holds a reset, the element defaults and the prose stylesheet. Unlayered StyleX outranking an element-level rule is the behaviour we want; layering it would invert that and let a straybody {}rule beat a component.- Static export.
output: "export"means no server runtime, soruntimeInjectionstaysfalse— there is nothing to inject styles at runtime.
aliases: { '@/*': ... } in the babel plugin config must match the @/* path
in tsconfig.json, or imports from @/app/tokens.stylex resolve to nothing and
their vars compile away.
Before calling it done
npm run buildpasses. A dev server that renders is not proof: StyleX failures are compile-time and silent, and dev mode emits readable class names production does not.- No element carries a
stylex.props()spread alongside aclassNameorstyleprop — including an implicit one from a{...props}spread placed after it. - No style value is imported from anything but a
.stylex.tsmodule. npm run lintandnpm run types:checkpass.
Signals
- GitHub stars
- 27
- Forks
- 1
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
stylex- Source
- github.com/joeymckenzie/joeymckenzie.tech