Skip to content

Module System

ECSS supports splitting styles across multiple files. One file can import enums and blocks from another: enums — as types for @param, blocks — for inheritance (extends) and contextual styles (@external).

@import

The @import directive imports named declarations from another .ecss file.

ecss
@import { Name1, Name2 } from "./path/to/file.ecss";

What you can import:

  • @enum — to use as a type in @param
  • @block — for inheritance via extends
  • @const — to use values from another file

Example: shared enums

ecss
// tokens.ecss
@enum Size {
  values: "sm", "md", "lg";
}

@enum Variant {
  values: "primary", "danger", "ghost";
}
ecss
// Button.ecss
@import { Size, Variant } from "./tokens.ecss";

@block Button {
  @param --variant Variant;
  @param --size Size;

  @if (--size == "sm") {
    padding: 4px 8px;
  }

  @if (--size == "md") {
    padding: 8px 16px;
  }

  @if (--size == "lg") {
    padding: 14px 28px;
  }
}

Inheritance

A @block can inherit styles from another block via the extends keyword. The parent block must be from the same file or imported via @import.

ecss
@block Child extends Parent {
  /* additional styles */
}

The descendant receives all of the parent's parameters and can add its own.

Example

ecss
// Shadow.ecss
@enum ShadowLevel {
  values: "sm", "md", "lg";
}

@block Shadow {
  @param --shadow ShadowLevel;

  @if (--shadow == "sm") {
    box-shadow: 0 1px 3px rgb(0 0 0 / 0.12);
  }

  @if (--shadow == "md") {
    box-shadow: 0 4px 12px rgb(0 0 0 / 0.15);
  }

  @if (--shadow == "lg") {
    box-shadow: 0 8px 24px rgb(0 0 0 / 0.2);
  }
}
ecss
// Button.ecss
@import { Shadow } from "./Shadow.ecss";

@enum Variant {
  values: "primary", "ghost";
}

@block Button extends Shadow {
  @param --variant Variant;

  display: inline-flex;
  padding: 8px 16px;
  border-radius: 6px;

  @if (--variant == "primary") {
    background: #646cff;
    color: #fff;
  }
}
tsx
import { EButton } from './Button.ecss';

<EButton as="button" params={{ variant: 'primary', shadow: 'md' }}>
  Button
</EButton>;

EButton accepts the parameters of both Button and Shadow — TypeScript knows all the allowed values.

@external

@external lets you extend the styles of another block in the context of the current one. It is declared inside a @block. The block referenced by @external must be imported beforehand:

ecss
@import { Button } from "./Button.ecss";

@block Toolbar {
  @param --dense? boolean;

  @external Button {
    border-radius: 4px;

    @if (--dense) {
      padding: 4px 8px;
    }
  }

  @external Button.Text {
    font-size: 13px;
  }
}

The Button.Text notation references the nested Text element of the Button block — such elements are declared via @element.

Inside @external the parameters of the current block (Toolbar) are available, but not those of the external one (Button).

Next steps