Skip to content

Conversation

@mellyeliu
Copy link
Member

@mellyeliu mellyeliu commented Dec 22, 2025

Implementation

Adding support for inline styles authoring with a new @stylexjs/inline-css package. This allows you to write styles inline in stylex.props() that are pre-compiled within the props visitor using much of the create logic for static and dynamic styles.

This is something we went back and forth on a few times, but ultimately felt that it's good to provide the optionality. We still recommend (and want to bake in enough friction) for people to use stylex.create namespaces for the majority of usecases for readability/maintainability reasons.

import * as stylex from '@stylexjs/stylex';
import * as css from '@stylex/inline-css';

<div {...stylex.props(
  css.display.flex,
  css.padding._16px,
  css.width['calc(100% - 20cqi)'],
  css.color(color),
)} />

The naming of all the above is up for discussion, as well as what styles we should build into this API. I'm also using Properties type from estree for type checking for a first pass, but there might be something better we can use.

Testing

Style types:

  • Static values
  • Leading underscores
  • Object key syntax
  • Dynamic inline styles
  • Contextual styles?

Tested within docs page the above +

  • Different merges of dynamic, regular, and inline styles
  • Named imports

Integration work:

  • Make work with valid-styles / some way to add linter validation
  • Double check minified keys (maybe should default disable this option) and other babel configs
  • Add docs
  • Fix types
  • Cleanup + refactor
  • Rethink package name + standard import alias

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Dec 22, 2025
@mellyeliu mellyeliu marked this pull request as draft December 22, 2025 09:17
@github-actions
Copy link

github-actions bot commented Dec 22, 2025

workflow: benchmarks/perf

Comparison of performance test results, measured in operations per second. Larger is better.

benchmarks@0.17.4 compare
node ./compare.js /tmp/tmp.d35VXteKA2 /tmp/tmp.FaAeH5QhnU

Results Base Patch Ratio
babel-plugin: stylex.create
· basic create 532 537 1.01 +
· complex create 66 67 1.02 +
babel-plugin: stylex.createTheme
· basic themes 444 455 1.02 +
· complex themes 34 34 1.00

@github-actions
Copy link

github-actions bot commented Dec 22, 2025

workflow: benchmarks/size

Comparison of minified (terser) and compressed (brotli) size results, measured in bytes. Smaller is better.

benchmarks@0.17.4 compare
node ./compare.js /tmp/tmp.lF24QdhFXY /tmp/tmp.t47Cz5ZOFS

Results Base Patch Ratio
@stylexjs/stylex/lib/cjs/stylex.js
· compressed 1,311 1,311 1.00
· minified 4,150 4,150 1.00
@stylexjs/stylex/lib/cjs/inject.js
· compressed 1,793 1,793 1.00
· minified 4,915 4,915 1.00
benchmarks/size/.build/bundle.js
· compressed 496,650 496,650 1.00
· minified 4,847,840 4,847,840 1.00
benchmarks/size/.build/stylex.css
· compressed 99,853 99,853 1.00
· minified 747,541 747,541 1.00

@mellyeliu mellyeliu changed the title [inline-css] add support for inline styles [inline-css] support for inline styles Dec 22, 2025
} & ((value: V) => StyleXStyles);

type InlineCSS = {
[Key in keyof Properties<string | number>]: InlineValue<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like everything in Properties is optional and the Required utility type can help.

Suggested change
[Key in keyof Properties<string | number>]: InlineValue<
[Key in keyof Required<Properties<string | number>>]: InlineValue<

It would be cool if StyleXCSSTypes.js also used csstype or at least the same thing.

Copy link
Collaborator

@nmn nmn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start, but a few changes are needed.

Comment on lines +10 to +18
const valueProxy = (_propName) =>
new Proxy(function () {}, {
get() {
return valueProxy('');
},
apply() {
return undefined;
},
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably not be a recursive proxy and the get() should throw an error similar to the stylex package saying you need to compile this away.

Comment on lines +22 to +25
if (typeof prop === 'string') {
return valueProxy(prop);
}
return undefined;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably just throw here directly and not define valueProxy at all.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, let's add Flow types to this and auto-generate the TS types from that.

Comment on lines +30 to +33
if (specifier.type === 'ImportNamespaceSpecifier') {
state.inlineCSSImports.set(specifier.local.name, '*');
} else if (specifier.type === 'ImportDefaultSpecifier') {
state.inlineCSSImports.set(specifier.local.name, '*');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ESM doesn't allow an arbitrary proxy for exports from a package. So maybe we ONLY allow a named or default import here?

I think limiting this to a named import makes the most sense right now.

Comment on lines +238 to +239
import * as css from '@stylexjs/inline-css';
stylex.props(css.display.flex);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import * as css from '@stylexjs/inline-css';
stylex.props(css.display.flex);
import {css} from '@stylexjs/inline-css';
stylex.props(css.display.flex);

Comment on lines +473 to +476
stylex.props([{
"color": color != null ? "x14rh7hd" : color,
"$$css": true
}, {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is important that that the style objects created by the inline-css package are hoisted to the module level as a constant and not inlined like this. We already have a utility for doing this somewhere.

Comment on lines +34 to +35
module.exports = inlineCSS;
module.exports.default = inlineCSS;
Copy link
Collaborator

@henryqdineen henryqdineen Dec 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like it's rare at this point to see frontend code be published CJS-only. Could this be written in ESM and then use babel at build time to create a CJS version?

I have a similar nitpick about styleq but I see there is an open PR for that. One advantage is that it would make the @stylexjs/stylex rollup bundle slightly smaller.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants