@evenfrost/react-inline-css-module
v1.2.0
Published
Auto transform CSS Module class name for React with Vite.
Maintainers
Readme
@evenfrost/react-inline-css-module
Vite plugin that rewrites styleName (and other configured props) to module-scoped className values, matching the behavior of babel-plugin-react-css-modules without needing Babel.
Why
- Use CSS Modules with
styleNamesyntax in Vite/React projects. - Works with multiple imported CSS Module files per component.
- Respects your prop ordering when merging
styleNameandclassName. - Emits warnings for missing class keys or non-string
styleNameprops. - Supports custom
*StyleNameprops mapped to arbitrary class props.
Install
npm install @evenfrost/react-inline-css-module
# or
yarn add @evenfrost/react-inline-css-moduleVite setup
// vite.config.ts
import react from '@vitejs/plugin-react';
import reactStylename from '@evenfrost/react-inline-css-module';
export default {
plugins: [
react(),
reactStylename({
attributeNames: {
// sourceProp: targetClassProp
styleName: 'className', // default
activeStyleName: 'activeClassName' // custom
},
// reactVariableName: 'React', // change if you use a different React import name
}),
],
};Options
attributeNames?: Record<string, string>
Map of props that should be treated likestyleName. Keys are the props containing CSS Module keys; values are the props that receive the transformed class string. Defaults to{ styleName: "className" }.reactVariableName?: string
If you import React under a different name, set it here soReact.createElementcalls are wrapped correctly.
Usage
/* style.module.css */
.app { color: #777; }
.info { color: green; }import './style.module.css';
export function App() {
return (
<div styleName="app">
<div>content</div>
<div styleName="info">info</div>
</div>
);
}Custom attribute example
examples/custom-attributes contains a runnable demo. Minimal setup:
// vite.config.ts
reactStylename({
attributeNames: {
togglerStyleName: "togglerClassName",
bodyStyleName: "bodyClassName",
wrapperStyleName: "wrapperClassName",
},
});// examples/custom-attributes/App.tsx
import "./style.module.css";
export function Dropdown({ open }: { open: boolean }) {
return (
<div wrapperStyleName="wrapper" wrapperClassName="dropdown-wrapper">
<button togglerStyleName="toggler" togglerClassName="dropdown-btn">
Toggle
</button>
<div
bodyStyleName={open ? "bodyOpen" : "bodyClosed"}
bodyClassName="dropdown-body"
>
Content
</div>
</div>
);
}Run the demo locally:
npm run example:devFor intrinsic DOM elements, custom target props are folded into className to avoid React DOM warnings; for custom components, the mapped target prop (e.g., activeClassName) is preserved.
TypeScript setup
Add the plugin’s JSX typings so custom *StyleName props are recognized:
// global.d.ts
/// <reference types="vite/client" />
/// <reference types="@evenfrost/react-inline-css-module/types/style-name" />Or add to tsconfig.json:
{
"compilerOptions": {
"types": ["@evenfrost/react-inline-css-module/types/style-name"]
}
}Scripts
npm run build— compile TypeScript and bundle the plugin.npm test— run Vitest suite.npm run example:dev— start the custom-attribute demo (Vite dev server).npm run example:build— build the demo.
Notes
- Only transforms
.jsx/.tsxfiles. - Warnings are logged when a referenced CSS Module key is missing or when a style prop is not a string.
