Introduction 

StyleX compiles style definitions into CSS during the frontend build. Fluid templates run later, on the server, and cannot call stylex.props(). The connector closes that gap with a manifest file.

What is StyleX? 

StyleX is a compile-time CSS-in-JS library developed by Meta (Facebook) and deployed in high-scale production applications including Facebook, Instagram, WhatsApp, and Threads. It is completely framework-agnostic and open source.

The Core Concept 

Instead of writing CSS classes or SCSS selector trees, you author styles using JavaScript objects. A build-time compiler (via Babel or unplugin/Vite) transforms supported style declarations into reusable atomic CSS rules. The compiler also produces metadata used by StyleX APIs and, in TYPO3, by a compatible Connector manifest producer. Do not depend on generated class names in templates or source code.

There is zero runtime style injection in the browser. The output is a standard static .css file.

// What you write (components/nav.stylex.js):
import * as stylex from '@stylexjs/stylex';
import { colors } from '../tokens/color-tokens.stylex.js';
import { spacing } from '../tokens/spacing-tokens.stylex.js';

export const styles = stylex.create({
  link: {
    color: colors.bodyText,
    padding: spacing.md,
    borderRadius: '4px',
  },
  active: {
    color: colors.primary,
    fontWeight: 'bold',
  },
});
Copied!
/* What StyleX emits into the compiled CSS bundle: */
.x1a2b3 { color: #212529; }
.x4c5d6 { padding: 1rem; }
.x7e8f9 { border-radius: 4px; }
.x9g0h1 { color: #ff8700; }
.x2i3j4 { font-weight: 700; }
Copied!

When two styles are composed (e.g. link and active), both define color. StyleX resolves the conflict at build time (or in PHP via the StyleX Connector) using a deterministic rule: the last style applied wins.

Core Advantages of StyleX 

Deterministic, Conflict-Free Styling 

  • The Problem with Traditional CSS/SCSS: The cascade and specificity create implicit ordering dependencies. Adding a class in one SCSS file can unexpectedly override or be overridden by rules in another file based purely on stylesheet order or selector specificity. Furthermore, developers and AI coding assistants alike frequently fail to take the load or bundling order of separate CSS/SCSS files into account, leading to component styles that are quietly and unintentionally overridden by other styles.
  • What StyleX Solves: Every CSS property maps to an atomic class with identical specificity (a single class selector). When two style definitions declare conflicting values for the same property, the last applied style strictly wins. Import order and stylesheet load order no longer dictate which rule applies, completely eliminating specificity battles, silent cascade overrides, and !important hacks.

Atomic CSS and token reuse 

StyleX compiles declared styles into atomic CSS and deduplicates equivalent declarations across the build. CSS size follows the unique rules the project uses; it is not tied one-to-one to the number of source files or components. Do not rely on a fixed growth curve. Keep styles statically discoverable and import only the recipes needed by the relevant entrypoint.

Design tokens and themes 

Use stylex.defineVars() for values that need to vary by theme or runtime scope. Keep token families in separate, named .stylex.js modules, then import the exported variable groups into recipes. StyleX's API abstracts the generated CSS variable identifiers; consume variables through their exports instead of hardcoding generated names.

// tokens/color-tokens.stylex.js
import * as stylex from '@stylexjs/stylex';

export const colors = stylex.defineVars({
  textPrimary: '#212529',
  textInverse: '#ffffff',
  accent: '#ff8700',
  surface: '#ffffff',
});
Copied!
// tokens/spacing-tokens.stylex.js
import * as stylex from '@stylexjs/stylex';

export const spacing = stylex.defineVars({
  compact: '0.5rem',
  normal: '1rem',
  spacious: '1.5rem',
});
Copied!

Import those tokens into component recipes rather than copying values. Use stylex.defineConsts() for shared values that are not themeable. Create component-specific token groups only when they form a deliberate reusable contract; keep one-off layout values in the recipe that uses them.

Use stylex.createTheme() to override token groups for a named theme. Keep theme identity separate from color mode: a brand theme such as ocean can support both light and dark modes, while mode describes the color-scheme variant. Use semantic token names such as textPrimary rather than names that encode a theme or mode.

// themes/ocean-theme.stylex.js
import * as stylex from '@stylexjs/stylex';
import { colors } from '../tokens/color-tokens.stylex.js';

export const oceanTheme = stylex.createTheme(colors, {
  accent: '#006b91',
  surface: '#f3fbff',
});
Copied!

Theme overrides may be sparse when omitted values inherit from a parent theme. Check every independently themed subtree and nested theme boundary so all consumed variables resolve to the intended values. If a surface can render outside its normal parent, provide a complete set of needed values or a safe default.

The connector resolves manifest keys; it does not infer keys from token or theme source files. A theme class used in server-rendered Fluid must be present in the manifest, for example as theme.ocean. The maintained Vite adapter documents static compiled stylex.create() styles; check whether the selected manifest producer also exports createTheme() classes. If it does not, add a consumer adapter that emits semantic theme keys or apply the theme in a JavaScript-owned surface. Validate theme keys with stylex:validate.

Dead Style Elimination 

Because all style rules are imported and referenced as ES modules in JavaScript, bundlers like Vite and Rollup can automatically tree-shake unused .stylex.js files or unreferenced style exports. Removing a TYPO3 component or retiring an obsolete element automatically removes its CSS from the production bundle.

Style Encapsulation Without a Component Framework 

StyleX does not provide CSS-Module-style selector scoping: generated class selectors exist in the shared stylesheet. Encapsulation comes from applying the generated classes only to the intended elements and composing styles through StyleX. Keep generated class strings out of templates, and do not treat a recipe module as a selector namespace. See StyleX authoring and themes for source and key naming.

Conditional Styling via Pure Logic 

Conditional styles do not require brittle class-string concatenations. With EXT:stylex_connector, conditional styling in Fluid templates is declarative:

<f:link.page
    class="{stylex:class(styles: 'Nav.link', when: {isActive: 'Nav.active'})}"
    pageUid="{item.data.uid}"
>
    {item.title}
</f:link.page>
Copied!

The ViewHelper resolves 'Nav.link' and, if the template variable isActive evaluates to true, layers 'Nav.active' on top, cleanly overriding conflicting properties.

CSS Layers (@layer) — Taming Specificity 

StyleX supports native CSS Cascade Layers (useCSSLayers: true), grouping atomic classes inside @layer stylex. When third-party frameworks like Bootstrap are also compiled into layers, an initial declaration:

@layer bootstrap, stylex, overrides;
Copied!

guarantees that StyleX styles override Bootstrap without requiring higher selector specificity or !important.

However, in many projects (including standard TYPO3 setups), Bootstrap is loaded unlayered (via CDN or standard JS bundle import). In CSS Cascade Level 5, unlayered styles take precedence over layered styles (Unlayered > Layered). To handle this, StyleX provides a powerful alternative: disabling CSS layers (useCSSLayers: false).

When useCSSLayers: false, the StyleX compiler automatically appends a :not(#\#) pseudo-class selector to every atomic class (e.g. .x1a2b3:not(#\#)). This bumps the selector specificity from (0,1,0) to (0,2,0), allowing StyleX atomic rules to cleanly override Bootstrap's unlayered element or single-class rules without cascade layers.

Future-Proof Architecture (Headless Ready) 

If a TYPO3 project transitions toward a hybrid or headless architecture (e.g. TYPO3 headless with React, Next.js, Vue, or Web Components), the .stylex.js source files can be used directly by those frontend frameworks without rewriting a single line of CSS.

StyleX Compared to Bootstrap CSS 

Bootstrap provides a comprehensive UI kit and 12-column grid. StyleX is an authoring system, not a component library.

Dimension Bootstrap CSS StyleX
Paradigm Pre-built utility classes & component CSS Compile-time atomic CSS-in-JS
Specificity Deep selector chains (.navbar-expand-lg .navbar-nav .nav-link) Flat atomic selectors with :not(#\#) bump (.x1abc:not(#\#))
Bundle Size Full bundle shipped ( 30-60 KB min+gz) Only used property-value rules emitted
Custom Overrides Requires fighting the cascade or using !important Deterministic property override + Specificity Bump
Tokens SCSS variable overrides Typed defineVars() generating CSS Custom Properties

Possible Coexistence in TYPO3 

Bootstrap provides the responsive layout grid and JavaScript components (modals, collapse). StyleX powers custom components and design system styling, overriding Bootstrap visual styles cleanly either via :not(#\#) specificity bumping (useCSSLayers: false) or via @layer when Bootstrap is layered.

StyleX Compared to Tailwind CSS 

Tailwind CSS uses utility classes in HTML markup (class="flex items-center gap-4 bg-orange-500"). StyleX defines styles in JavaScript objects and applies atomic classes through compiled references.

Feature Tailwind CSS StyleX
HTML Markup Long, verbose class attribute strings Clean template attributes (styles: 'Button.primary')
Conflict Resolution Depends on stylesheet generation order Deterministic: last argument strictly wins
Design Constraint Arbitrary values easy to slip in (bg-[#ff8700]) Static build enforcement against token definitions
CSS Purging Regex-based source file scanning (safelisting needed) Native module graph tree-shaking
Typing Editor extensions (Tailwind CSS IntelliSense) Native TypeScript / JavaScript type safety

The Astryx Design System 

Astryx is Meta’s open-source design system built on StyleX. It provides over 170 accessible, themeable components used internally across Meta products.

Because Astryx is authored entirely in StyleX, its design tokens, color ramps, and atomic CSS share the exact same compiler pipeline as custom StyleX code. For TYPO3, Astryx tokens can serve as the design token baseline in tokens.stylex.js, unifying custom Fluid components with Meta's production-tested accessibility and dark-mode foundation.

StyleX and AI / LLM-Assisted Development 

Modern development workflows increasingly leverage AI coding assistants (Cursor, Claude, Codex, GitHub Copilot). StyleX delivers substantially higher accuracy and fewer hallucinations when generated by LLMs:

  1. Typed Objects vs. Hallucinated Strings: In Tailwind or Bootstrap, an LLM might generate plausible-looking but non-existent class strings (such as bg-blue-6000 or text-primary-semibold). StyleX styles are typed JavaScript objects; invalid properties fail at build time.
  2. Constrained Solution Space: When an AI assistant reads tokens.stylex.js, it is constrained to valid token properties (colors.primary, spacing.lg), preventing design system drift.
  3. Natural Context Co-location: A single component's styling lives entirely within its .stylex.js file, fitting cleanly within an LLM's context window.
  4. Predictable Logic: The rule that "the second argument overrides conflicting properties of the first" is easy for LLMs to reason about mathematically without simulating the browser CSS cascade.
  5. Immunity to CSS/SCSS Load-Order Blindness: LLMs typically generate styles in component isolation and notoriously struggle to anticipate the implicit load, import, or concatenation order of CSS/SCSS files across a project. In traditional stylesheets, an LLM frequently produces selectors that look correct in isolation but are quietly and unintentionally overridden by rules from other stylesheets loaded later in the document head or build sequence. With StyleX's atomic architecture and flat specificity, load order does not dictate style precedence. Conflicts are resolved deterministically at the call site (stylex.props() / {stylex:class()}), ensuring LLM-generated component styles render as intended without accidental cascade overrides.

AI Agent Workflows & typo3-stylex Skill 

When working with an AI agent or coding assistant (such as Antigravity, Cursor, or Claude Code), installing the typo3-stylex Skill can be useful. It provides the agent with dedicated instructions, best practices, and integration workflows for installing, configuring, and verifying skom/stylex-connector, Vite asset pipelines, and atomic styling in TYPO3.

The typo3-stylex Skill can be found in the ai-typo3-integrator-plugin at the following URL: https://github.com/Starraider/ai-typo3-integrator-plugin/tree/main/skills/typo3-stylex

StyleX Benefits for TYPO3 Content Blocks 

The TYPO3 Content Blocks initiative (friendsoftypo3/content-blocks / TYPO3 Core Content Blocks in v14) provides a declarative, directory-based format for structuring custom content elements. While Content Blocks conventionally loads individual frontend.css files via <f:asset.css>, combining Content Blocks with StyleX via EXT:stylex_connector elevates the architecture to enterprise-grade web performance.

Shared StyleX CSS for Content Blocks 

A traditional Content Block can register a stylesheet using:

<f:asset.css identifier="cb-quote" href="{cb:assetPath()}/frontend.css" />
Copied!

If every block registers its own stylesheet, a page with many different blocks may include several CSS assets.

The StyleX approach:

  • Import the required Content Block .stylex.js recipes into an appropriate Vite entry and emit their compiled rules through the project's shared CSS delivery path.
  • Have Fluid reference manifest keys such as {stylex:class(styles: 'quote.root')}; do not add a per-block CSS include for those StyleX rules.
  • The actual number of requests depends on the configured build and asset delivery. A shared bundle can reduce stylesheet fragmentation, but StyleX alone does not guarantee a particular request count.

Atomic CSS reuse across components 

StyleX can reuse identical compiled declarations across recipes. The final CSS size depends on the distinct declarations, variants, selectors and build entries required by the application. Avoid predicting a fixed linear or logarithmic growth curve. Multiple Content Blocks may use repeated declarations such as:

  • Card, Testimonial, and Teaser all define padding: 1.5rem;
  • Hero, Banner, and FeatureGrid all define display: flex; align-items: center;
  • Multiple buttons across different blocks define identical border radii and transitions.

The StyleX Advantage:

  • Repeated declarations can share compiled atomic rules within the same delivered build output.
  • New blocks still add CSS when they introduce new declarations, variants or responsive states.
  • Measure the production bundle rather than assuming that adding blocks has negligible cost.

Strict Brand & Design Token Adherence 

Independent Content Block CSS files are notorious for design drift: developers copy-paste arbitrary hex colors (#1a73e8), custom paddings (18px), and inconsistent font sizes into separate frontend.css files.

The StyleX Advantage:

  • Content Blocks import typed design tokens directly from the sitepackage:

    import * as stylex from '@stylexjs/stylex';
    import { colors } from '../../../../Resources/Private/JavaScript/StyleX/tokens/color-tokens.stylex.js';
    import { spacing } from '../../../../Resources/Private/JavaScript/StyleX/tokens/spacing-tokens.stylex.js';
    import { shape } from '../../../../Resources/Private/JavaScript/StyleX/tokens/shape-tokens.stylex.js';
    import { typography } from '../../../../Resources/Private/JavaScript/StyleX/tokens/typography-tokens.stylex.js';
    
    export const styles = stylex.create({
      root: {
        backgroundColor: colors.surface,
        padding: spacing.spacious,
        borderRadius: shape.radiusMedium,
      },
      title: {
        fontFamily: typography.fontFamily,
        fontSize: typography.sizeXl,
        color: colors.accent,
      },
    });
    Copied!
  • Compile-Time Validation: Any mistyped token (colors.primry) or invalid CSS property is flagged immediately during npm run build or ddev vite.
  • Consistent rebranding: Updating a shared semantic token updates recipes that consume it after the relevant build output is regenerated.

Deterministic Variant Composition in Fluid 

Content Blocks frequently provide backend select boxes or checkboxes for visual variants (e.g. background theme, highlighted state, alignment).

In traditional CSS, this requires fragile string concatenation:

<div class="cb-card {f:if(condition: isFeatured, then: 'cb-card--featured')} {f:if(condition: isDark, then: 'cb-card--dark')}">
Copied!

This pattern frequently breaks down when .cb-card--featured and .cb-card--dark fight over the same CSS properties (e.g. border-color or color) because selector specificity and declaration order in the CSS file dictate the winner.

The StyleX Advantage:

  • Handled cleanly via the connector's Fluid ViewHelper:

    <div class="{stylex:class(
        styles: 'Card.root',
        when: {isFeatured: 'Card.featured', isDark: 'Card.dark'}
    )}">
    Copied!
  • The PHP StylexManifestService resolves property collisions deterministically: the last active style strictly wins on a per-property level. There are no class collision bugs or specificity fights.

Coexistence with Third-Party & Vendor Content Blocks 

Projects do not have to rewrite every Content Block into StyleX:

  • Custom In-House Blocks: Authored in StyleX for maximum performance and token integration.
  • Third-Party / Marketplace Blocks: Load their pre-compiled frontend.css files cleanly isolated within CSS Cascade Layers (@layer vendor-blocks, stylex;).
  • Sitepackage StyleX utility classes can deterministically override vendor Content Block styling when customized branding is required, without resorting to !important.

The build writes stylex-manifest.json. Its styles object maps a style key to a className and, when available, a compiler conflict map. TYPO3 loads the manifest and the ViewHelper writes the resolved classes into a class attribute.

StyleX source -> Vite build -> stylex-manifest.json
                                   |
                                   v
Fluid template <- StyleX Connector <- registered manifest
Copied!

Requirements 

The extension targets TYPO3 12.4, 13.4, and 14.3 or later within their respective major lines. It requires PHP 8.1 through 8.4 and typo3/cms-fluid in the same supported TYPO3 range.

The sitepackage also needs a frontend build that produces a compatible manifest. The connector does not compile StyleX source files and it does not provide a Vite configuration.

What the extension provides 

  • StylexRegistry registers one or more manifest paths.
  • StylexManifestService loads and caches the merged manifest data.
  • stylex:class resolves base, conditional, and fallback style keys in Fluid.
  • A Site Set and TypoScript files can include the optional CSS delivery and standalone stylesheet ordering.
  • An optional maintained static Vite adapter produces versioned manifests.
  • stylex:validate checks required keys, collisions and declared CSS hashes.

The ViewHelper namespace is registered globally by ext_localconf.php. Templates can therefore use {stylex:class(...)} without declaring the namespace themselves.

For source organization, token naming, themes and CSS boundaries, see StyleX authoring and themes. For the StyleX API, read the StyleX documentation.