Technology Aug 24, 2026 · 5 min read

How to build an FSCSS module like st-core.fscss

To build an FSCSS module like st-core.fscss, create a stylesheet of reusable @define mixins, expose a small public API, and compile/test it with the FSCSS CLI. st-core follows this pattern for design tokens, layout helpers, charts, stat cards, and progress bars. 1. Learn the module structu...

DE
DEV Community
by FSCSS tutorial
How to build an FSCSS module like st-core.fscss

To build an FSCSS module like st-core.fscss, create a stylesheet of reusable @define mixins, expose a small public API, and compile/test it with the FSCSS CLI. st-core follows this pattern for design tokens, layout helpers, charts, stat cards, and progress bars.

1. Learn the module structure

An FSCSS module is a stylesheet of reusable style definitions that other FSCSS files can import.

A practical module should contain:

  • Private design tokens and helper logic
  • Public mixins with a consistent naming convention
  • Parameter defaults
  • Selector arguments so consumers can choose their own class names
  • Documentation and examples
  • A compiled CSS output for production

Typical project layout:

my-core.fscss
README.md
examples/
  demo.fscss
dist/
  my-core.css
package.json

2. Define a public API

Use a namespace to avoid collisions. Parameters must be read with @use(). For full rules, wrap the body in a backtick string block and target the selector with @use(selector){ ... }.

@define mc-root(root:root){`
:@use(root){
  --mc-bg: #10131a;
  --mc-surface: #191e28;
  --mc-card: #222938;
  --mc-accent: #4f9cff;
  --mc-text: #eef4ff;
  --mc-muted: #8491a7;
  --mc-radius: 12px;
  --mc-space: 20px;
  --mc-chart-line-width: 1.5px;
}
`}

Verify the exact syntax against the FSCSS version you ship against. st-core.fscss requires FSCSS 1.1.24 or later.

3. Build reusable mixins

A mixin should generate one coherent component or behavior.

Container

@define mc-container(st:body){`
  @use(st){
    width: 100%;
    max-width: 1100px;
    margin-inline: auto;
    padding: var(--mc-space);
  }
`}

Card

@define mc-card(st:.mc-card){`
  @use(st){
    background: var(--mc-card);
    border: 1px solid color-mix(in srgb, var(--mc-accent) 18%, transparent);
    border-radius: var(--mc-radius);
    padding: var(--mc-space);
    color: var(--mc-text);
  }
`}

Progress bar

@define mc-progress(st:.mc-progress, default-width: 0%){`
  @use(st){
    width: var(--mc-progress-width, @use(default-width));
    height: 8px;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--mc-accent), #9bc7ff);
    transition: width 400ms ease;
  }
`}

The mixin establishes structure; CSS custom properties let individual instances override values.

4. Create a chart data mixin

st-core stores chart values in custom properties (--st-p1--st-p8). The fill, line, and dots inherit them. Values are supplied on a natural 0–100 scale (100 = top); the mixin inverts them for CSS coordinates.

@define mc-chart-points(
  p1: 0, p2: 0, p3: 0, p4: 0,
  p5: 0, p6: 0, p7: 0, p8: 0
){
  --mc-p1: num(100 - @use(p1))%;
  --mc-p2: num(100 - @use(p2))%;
  --mc-p3: num(100 - @use(p3))%;
  --mc-p4: num(100 - @use(p4))%;
  --mc-p5: num(100 - @use(p5))%;
  --mc-p6: num(100 - @use(p6))%;
  --mc-p7: num(100 - @use(p7))%;
  --mc-p8: num(100 - @use(p8))%;
}

5. Render the chart with CSS

Use clip-path: polygon(). This is pure CSS—no SVG, canvas, or JS charting library.

Area fill

@define mc-chart-fill(st:.mc-chart-fill){`
  @use(st){
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, var(--mc-accent) 35%, transparent);
    clip-path: polygon(
      0% var(--mc-p1),
      14% var(--mc-p2),
      28% var(--mc-p3),
      42% var(--mc-p4),
      57% var(--mc-p5),
      71% var(--mc-p6),
      85% var(--mc-p7),
      100% var(--mc-p8),
      100% 100%,
      0% 100%
    );
  }
`}

Line stroke (thin polygon with return path)

@define mc-chart-line(st:.mc-chart-line){`
  @use(st){
    position: absolute;
    inset: 0;
    background: var(--mc-accent);
    filter: drop-shadow(0 0 6px var(--mc-accent));
    clip-path: polygon(
      0% var(--mc-p1),
      14% var(--mc-p2),
      28% var(--mc-p3),
      42% var(--mc-p4),
      57% var(--mc-p5),
      71% var(--mc-p6),
      85% var(--mc-p7),
      100% var(--mc-p8),
      100% calc(var(--mc-p8) + var(--mc-chart-line-width)),
      85% calc(var(--mc-p7) + var(--mc-chart-line-width)),
      71% calc(var(--mc-p6) + var(--mc-chart-line-width)),
      57% calc(var(--mc-p5) + var(--mc-chart-line-width)),
      42% calc(var(--mc-p4) + var(--mc-chart-line-width)),
      28% calc(var(--mc-p3) + var(--mc-chart-line-width)),
      14% calc(var(--mc-p2) + var(--mc-chart-line-width)),
      0% calc(var(--mc-p1) + var(--mc-chart-line-width))
    );
  }
`}

For production-quality curves you may prefer SVG or canvas; the CSS technique is ideal for small, fixed-point visualizations.

6. Import and use the module

@import((*) from my-core)

@mc-root()
@mc-card(.stat-card)
@mc-chart-fill(.chart-fill)
@mc-chart-line(.chart-line)

.chart {
  position: relative;
  width: 100%;
  height: 220px;
  overflow: hidden;
  background: var(--mc-surface);
  border-radius: var(--mc-radius);

  @mc-chart-points(20, 35, 33, 30, 48, 35, 66, 37)
}

.chart-line {
  --mc-accent: #55d6be;
}

Corresponding HTML:

<div class="stat-card">
  <strong>Revenue</strong>
  <span>$84,201</span>
</div>

<div class="chart">
  <div class="chart-fill"></div>
  <div class="chart-line"></div>
</div>

st-core uses the same consumer pattern: import the module, call the component mixins, then place the generated classes in HTML.

7. Support runtime updates

Because data lives in custom properties, JavaScript only needs to write variables:

function updateChart(chart, values) {
  values.forEach((value, index) => {
    chart.style.setProperty(
      `--mc-p${index + 1}`,
      `${100 - value}%`
    );
  });
}

updateChart(document.querySelector('.chart'), [
  40, 75, 60, 45, 80, 50, 70, 30
]);

JavaScript supplies data; CSS remains responsible for rendering.

8. Compile and test

npm install -g fscss
fscss examples/demo.fscss dist/demo.css

Test at least:

  • Mixins with default arguments
  • Mixins with custom selectors
  • Multiple component instances
  • Missing or invalid values
  • Responsive widths
  • CSS custom-property overrides
  • Compiled output in browsers (no FSCSS runtime)

For production, compile the module into CSS. st-core documents CDN/runtime mode for prototypes and compiled mode for deployment.

Recommended API design

@mc-root()
@mc-container(selector)
@mc-card(selector)
@mc-chart-points(values...)
@mc-chart-fill(selector)
@mc-chart-line(selector)
@mc-chart-grid(selector, rows, columns)
@mc-progress(selector, default-width)

Keep implementation details private, prefix every generated variable and class, document every parameter, and provide one minimal example per mixin. That combination is what makes a module like st-core.fscss reusable rather than merely a collection of CSS snippets.

Sources

DE
Source

This article was originally published by DEV Community and written by FSCSS tutorial.

Read original article on DEV Community
Back to Discover

Reading List