Feature: allow a custom module file filter (support a bare `css.ts` convention)

Author: o-alexandrovCreated Jul 20, 2026Updated Jul 23, 2026

Summary

Allow consumers to customize which files @vanilla-extract/vite-plugin (and @vanilla-extract/compiler) treat as Vanilla Extract modules, so a bare css.ts filename convention can be used instead of the *.css.ts suffix.

Today the filter is a hardcoded const in @vanilla-extract/integration:

typescript
export const cssFileFilter = /\.css\.(js|cjs|mjs|jsx|ts|tsx)(\?used)?$/;

It is imported directly by the Vite plugin and the compiler with no way to override it.

css.ts vs *.css.ts the actual difference (re: your question in #1763)

They are not the same. The current filter requires a non-empty prefix before .css.ts (*.css.ts). It will not match a file literally named css.ts.

We co-locate one style file per component directory and want to name it just css.ts:

button/
  index.tsx
  css.ts        <- not matched today; must be button.css.ts
tooltip/
  index.tsx
  css.ts

Requiring the prefix forces a redundant, per-file token (button.css.ts, tooltip.css.ts) that:

  • duplicates the directory name in the filename with zero added information, and
  • has to be renamed every time the component is renamed (the style file drifts out of sync otherwise).

The convention itself (single fixed filename co-located in each component folder) is common and, for us, applied across a large multi-repo workspace.

Why this is distinct from #1574

#1574 is about a consumed third-party library whose emitted .css.ts/.css.js files clash with VE processing, solvable by controlling build output (emit .js, not .css.js). This request is about the authoring convention in first-party source; there is no build-output angle. It cannot be worked around by changing what a dependency ships.

Current workaround and why it's fragile

With no public override, the only options are:

  1. Patch @vanilla-extract/integration on disk after each install to rewrite the regex. In a multi-repo/workspace setup a single missed copy silently leaves css.ts files untransformed, which surfaces later at runtime as Styles were unable to be assigned to a file.
  2. Maintain a fork of the plugin (what we currently do).

Both are avoidable with a first-class option.

Proposal

A single additive, backwards-compatible option threaded through the plugin and compiler, defaulting to the existing cssFileFilter so nothing changes when omitted:

typescript
vanillaExtractPlugin({
  // treat a bare `css.ts` as the VE module convention
  cssFileFilter: /(?:^|[/\\])css\.(js|cjs|mjs|jsx|ts|tsx)(\?used)?$/,
});

Implemented in #1773 (~80 lines: vite-plugin transform gate + HMR invalidation, compiler module scanner + file-scope transform, defaulting to the current filter).

On the footgun concern

I understand the reluctance to expose the filter, a user-supplied regex can drop the js/jsx/tsx/mjs/cjs variants or otherwise misbehave. Happy to constrain the surface however you prefer (validate the shape, accept a set of extensions rather than a raw RegExp, document the caveats, etc.). I'd rather agree on the right shape here before iterating on the PR.

Source: vanilla-extract-css/vanilla-extract