🇺🇸 English version | 🇷🇺 Русская версия
Extended CSS — write typed, component-oriented styles in .ecss files and compile them to plain CSS plus framework components
You write a .ecss file:
@enum Variant {
values: "primary", "ghost";
}
@block Button {
@param --variant Variant;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
@if (--variant == "primary") {
background: #6c2bd9;
color: white;
}
}
…and get a fully typed component, backed by plain CSS:
import { EButton } from './Button.ecss';
<EButton as="button" params={{ variant: 'primary' }} onClick={onClick}>
Click me
</EButton>;- Typed components from styles —
@block,@element,@paramand@enumcompile to framework components with full TypeScript types. Passing an enum value that doesn't exist won't compile. - Real CSS output —
.ecsscompiles to plain, modern CSS files. Typed params become CSS custom properties at runtime; there is no CSS-in-JS style engine. - Conditional styling —
@if/@elseover typed params, resolved through CSS custom properties. - Reusable building blocks —
@const,@enum,@import,@externaland project-wideglobalImports. - Framework adapters — React, Vue, Svelte, Solid, Astro and vanilla DOM share the same
.ecsssources. - Fast — the parser is written in Rust (napi-rs) with a WebAssembly fallback.
- First-class tooling — a Vite plugin with HMR and a VS Code extension (diagnostics, completion, hover, go-to-definition).
| Package | Description |
|---|---|
@ecss/parser |
High-performance parser written in Rust (napi-rs); parses ECSS source into an AST. |
@ecss/compiler |
Converts ECSS source to CSS, JS bindings and TypeScript declarations. |
@ecss/config |
Config schema, defineConfig helper, loader and project cache. |
| Package | Description |
|---|---|
@ecss/vite-plugin |
Transforms .ecss files into CSS + JS with HMR support. |
| Package | Description |
|---|---|
@ecss/react-adapter |
Generates typed React components from ECSS blocks. |
@ecss/vue-adapter |
Generates Vue 3 components from ECSS blocks. |
@ecss/svelte-adapter |
Generates Svelte 4/5 components from ECSS blocks. |
@ecss/solid-adapter |
Generates SolidJS components from ECSS blocks. |
@ecss/astro-adapter |
Generates Astro components from ECSS blocks. |
@ecss/dom-adapter |
Vanilla JS/TS components wrapping ECSS blocks via the native DOM API. |
| Package | Description |
|---|---|
@ecss/language-service |
Diagnostics, completions, hover, definition, references and symbols for .ecss files. |
| ECSS — Extended CSS (VS Code) | Editor extension built on the language service. Available on the VS Code Marketplace. |
Using Vite + React as an example.
1. Install
npm install -D @ecss/vite-plugin @ecss/config @ecss/react-adapter2. Register the plugin in vite.config.ts:
import ecss from '@ecss/vite-plugin';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react(), ecss()],
});3. Configure ECSS in ecss.config.ts — the config is bundler-agnostic and read by the plugin:
import { defineConfig } from '@ecss/config';
import { reactAdapter } from '@ecss/react-adapter';
export default defineConfig({
adapters: [reactAdapter()],
defaultAdapter: 'react',
});4. Write a block in Button.ecss:
@block Button {
padding: 8px 16px;
border-radius: 6px;
}
5. Use the generated component:
import { EButton } from './Button.ecss';
export function App() {
return <EButton as="button">Click me</EButton>;
}The component name is the prefix + the block name (@block Button → EButton).
Full guides and reference live at ecss.webea.ch — directives (@block, @enum, @param, @if, @const, @import, @external, …), configuration and per-adapter docs.
Built and maintained by Ruslan Martynov
Found a bug or have a suggestion? Open an issue or send a pull request.
Distributed under the MIT License.