Skip to content

Adapters

An adapter turns @block declarations into typed components for a specific framework. All adapters share a common API — it is described on this page; the pages for individual adapters cover only framework-specific details.

AdapteridTypeWhat it generatesRequirements
Reactreactinlinea component in the .ecss moduleReact 18+
Vuevueinlinea component in the .ecss moduleVue 3.3+
Sveltesveltemodule-based.svelte filesSvelte 4+
SolidJSsolidmodule-based.jsx filessolid-js 1.8+
Astroastromodule-based.astro filesAstro 4/5
Vanilla JS (DOM)dominlineclasses in the .ecss modulebrowser (no framework)

inline — the component code is embedded directly into the compiled .ecss module. module-based — the adapter generates real framework files (.svelte/.astro/.jsx) into the internal .ecss/ directory, and imports of ./X.ecss are redirected to them. In both cases you simply import the component from the .ecss file — the difference is invisible.

Setup

The adapter is registered in ecss.config.ts via defineConfig from @ecss/config. defaultAdapter specifies which adapter is applied to .ecss files by default (the value is the adapter's id from the table above):

ts
// ecss.config.ts
import { defineConfig } from '@ecss/config';
import { reactAdapter } from '@ecss/react-adapter';

export default defineConfig({
  adapters: [reactAdapter()],
  defaultAdapter: 'react',
});

Multiple adapters in one project

You can register several adapters at once in adapters — for example, Astro for pages and React for interactive islands. The same @block will be available in both frameworks:

ts
// ecss.config.ts
import { defineConfig } from '@ecss/config';
import { astroAdapter } from '@ecss/astro-adapter';
import { reactAdapter } from '@ecss/react-adapter';

export default defineConfig({
  adapters: [astroAdapter(), reactAdapter()],
  defaultAdapter: 'astro',
});

defaultAdapter applies to ordinary ./X.ecss imports. To get the component for a different adapter, append the query suffix ?<id> to the path, where <id> is the adapter identifier from the table above (react, vue, svelte, solid, astro, dom):

astro
---
// Astro page — the default adapter
import { EButton } from './Button.ecss';
---
tsx
// React island — explicitly select the React variant of the same block
import { EButton } from './Button.ecss?react';

Imports with the ?<id> suffix are fully typed as well. The suffix works with any registered adapter regardless of defaultAdapter.

Common API

The component name is formed as {prefix}{BlockName} (the default prefix is E): @block ButtonEButton. The component is imported directly from the .ecss file.

The params prop

The block's parameters are passed through a single params prop (in the DOM adapter, a constructor option). Their types come from the generated {Block}Params interface, so you cannot pass a value that is not part of an @enum.

params is required if the block has at least one required @param (without ?); otherwise it can be omitted.

The as prop

By default the component renders as a <div>. The as prop accepts any HTML tag and changes the root element; typing narrows the set of allowed attributes to the chosen tag (as="a" exposes href, as="button" exposes type, and so on).

The exception is Astro: there as works too, but there is no per-tag attribute narrowing (any attribute is accepted).

class, style, and attributes

ECSS sets the block's class, the CSS variables from params, and data attributes on the root element. What you pass to the component is merged with these values: your class is added to the block's class, style is added to the CSS variables, and the remaining attributes and handlers land on the root element.

Sub-components (@element)

If a @block declares @element, they are available as nested components through static properties of the root: <EButton.Icon>. Sub-components support the same as prop but do not accept params.

The componentNamePrefix option

All adapter factories accept a componentNamePrefix option — the component name prefix (the default is 'E'):

ts
reactAdapter({ componentNamePrefix: 'My' }); // → MyButton, MyCard
OptionTypeDefaultDescription
componentNamePrefixstring'E'Component name prefix. The first character must be [A-Z], the rest [a-zA-Z0-9_].

An invalid prefix (one that does not match /^[A-Z][a-zA-Z0-9_]*$/) results in a build-time error.

Which adapter to choose

  • Using a framework — pick the adapter for that framework (React / Vue / Svelte / SolidJS / Astro).
  • Building a static site or SSR without client-side JS — Astro (server-rendered, zero JS in the browser by default).
  • Writing plain JS without a framework — Vanilla JS (DOM).

See also