React
@ecss/react-adapter generates typed React components from @block and @element declarations. The adapter's id is 'react'.
Installation
npm i -D @ecss/react-adapterpnpm add -D @ecss/react-adapteryarn add -D @ecss/react-adapterRequires react version 18 or higher to be installed.
Setup
The adapter is registered in ecss.config.ts via defineConfig from @ecss/config — the config is not tied to any particular bundler; it is read by the ECSS plugin of your bundler. defaultAdapter sets the adapter applied to .ecss files by default:
// ecss.config.ts
import { defineConfig } from '@ecss/config';
import { reactAdapter } from '@ecss/react-adapter';
export default defineConfig({
adapters: [reactAdapter()],
defaultAdapter: 'react',
});Usage
Components are imported directly from the .ecss file — one per @block. The component name is formed as {prefix}{BlockName} (the default prefix is E): @block Button → EButton.
import { EButton } from './Button.ecss';
<EButton as="button" params={{ variant: 'primary' }} onClick={handleClick}>
Click me
</EButton>;The params prop
The block's parameters are passed through a single params prop. Their types come from the generated {Block}Params interface (for example ButtonParams), so you cannot pass a non-existent @enum value.
params is required if the block has at least one required @param (without ?); if all parameters are optional or there are none at all, the prop can be omitted.
<EButton params={{ variant: 'primary' }} /> // variant is required
<ECard /> // Card has all parameters optionalThe as prop
By default the component renders as a <div>. The as prop accepts any HTML tag and changes the root element. The component is typed with a generic parameter based on the chosen tag, so the set of allowed HTML attributes narrows automatically:
<EButton as="button" type="submit" params={{ variant: 'primary' }}>Submit</EButton>
<EButton as="a" href="/about" params={{ variant: 'ghost' }}>Link</EButton>With as="a", href, target, and other <a> attributes are available; with as="button", type, disabled, and so on.
className, style, ref, and the remaining props
className— concatenated with the block's class without overriding it;style— merged on top of the CSS variables generated fromparams;ref— forwarded to the root DOM element;- all other props (
onClick,aria-*,data-*, …) are forwarded to the root element as is.
Sub-components (@element)
If a @block contains @element, they become nested components through static properties of the root:
import { EButton } from './Button.ecss';
<EButton params={{ withIcon: true }}>
<EButton.Icon>
<svg>{/* … */}</svg>
</EButton.Icon>
<EButton.Text>Click me</EButton.Text>
</EButton>;Sub-components support the same as prop (the default is <div>) but do not accept params.
Options
The factory's only option is componentNamePrefix (the component name prefix, default 'E'): reactAdapter({ componentNamePrefix: 'My' }) → MyButton. For more details, see the adapters overview.
React version support
The adapter detects the major version of React installed in the project and adjusts the generated code:
- React 19+ —
refis passed as a regular prop; - React 18 — the component is wrapped in
forwardRef.
The version is read from react/package.json relative to the project root and cached. If React cannot be resolved, the adapter prints a warning and uses React 19 as the default.
See also
- Configuration — the
adaptersanddefaultAdapteroptions @block— declaring blocks@element— sub-components@param— parameters and their types- Data types — parameter value types