Astro
@ecss/astro-adapter generates typed Astro components from @block and @element declarations. The adapter's id is 'astro'.
Unlike the React/Vue adapters, the Astro adapter is module-based: it generates real .astro files into the .ecss/astro/ directory, and imports of ./X.ecss are redirected to them automatically by the ECSS plugin. This is transparent to you — the component is imported from the .ecss file as usual.
Installation
npm i -D @ecss/astro-adapterpnpm add -D @ecss/astro-adapteryarn add -D @ecss/astro-adapterRequires astro version 4 or 5 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 { astroAdapter } from '@ecss/astro-adapter';
export default defineConfig({
adapters: [astroAdapter()],
defaultAdapter: 'astro',
});Usage
Each @block turns into an Astro component that is imported directly from the .ecss file. The component name is formed as {prefix}{BlockName} (the default prefix is E): @block Button → EButton. Content is passed through the default slot.
---
import { EButton } from './Button.ecss';
---
<EButton as="button" params={{ variant: 'primary' }}>
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 optional -->The as prop
By default the component renders as a <div>. The as prop accepts the name of any HTML tag and changes the root element:
<EButton as="button" type="submit" params={{ variant: 'primary' }}>Submit</EButton>
<EButton as="a" href="/about" params={{ variant: 'ghost' }}>Link</EButton>Any HTML attributes are passed to the root element as is (typing accepts any attribute; there is no per-tag narrowing here).
class, style, and attributes
ECSS sets the block's class, the CSS variables from params, and data attributes on the root element. What the consumer passes is merged with these values:
class— the consumer's class is added to the block's class without overriding it;style— added to the CSS variables generated fromparams;- the remaining attributes (
id,aria-*,data-*,href, …) are forwarded to the root element and win on collision withdataattributes.
Sub-components (@element)
If a @block contains @element, they become nested components through static properties of the root and are available in the template via dot notation:
<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'): astroAdapter({ componentNamePrefix: 'My' }) → MyButton. For more details, see the adapters overview.
Server-side rendering
Astro components are rendered on the server — by default not a single byte of client-side JS is sent to the browser. The block's class, the CSS variables, and the data attributes are computed once in the frontmatter and inlined directly into the HTML at build/SSR time, and the styles are included as <style>. Ideal for static pages.
JS reaches the browser only if you explicitly mark the island with a client:* directive.
See also
- Configuration — the
adaptersanddefaultAdapteroptions @block— declaring blocks@element— sub-components@param— parameters and their types- Data types — parameter value types