DEV Community

FSCSS
FSCSS

Posted on

FSCSS v1.2.0 lets you write mixins directly in `style="..."` — here's why that's a bigger deal than it sounds

Up until v1.2.0, FSCSS syntax fully resolved inside <style> blocks. Inline style attributes were mostly just... inline CSS, the regular kind.

That changed in v1.2.0. Boot now processes every element's style attribute the same way it processes a <style> block. Same compiler, same pipeline, same @define mixins, same arrays. The practical result: you can call a mixin straight from an attribute, and combined with the JS API, you can recompile it on the fly.

Here's what that looks like, and why it's more useful than "less typing."

The setup

<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.0/runtime.min.js" async></script>

<style>
  @define btn-style(bg: #636EE7){
    padding: 10px 20px;
    color: color-mix(#dddddd, @use(bg));
    background: @use(bg);
    border: 2px solid;
    border-radius: 25px;
    font-weight: 700;
  }
</style>

<button style="@btn-style(#1a2a4f)">Search</button>
<button style="@btn-style(#f00f00)">Search</button>
<button style="@btn-style(#4f4f4f)">Search</button>
Enter fullscreen mode Exit fullscreen mode

three buttons: fscss

One @define block, declared once. Three buttons, each calling it with a different color. No repeated class names, no utility soup, no separate stylesheet just to vary one property per element. On boot, FSCSS walks every style attribute, runs it through the same compiler that processes <style> blocks, and writes the compiled CSS back in place.

Where it gets interesting: dynamic updates

Inline processing on its own is a nice shorthand. Paired with the JS API, it becomes something closer to a lightweight styling engine.

<button style="
@arr colors[#1E2783, #8C29B2, #C41348, #0098d0]
@btn-style(@arr.colors!.randint)
" onclick="update(this)">Click</button>

<script>
  const update = async (btn) => {
    const newStyle = await xfscss.process("@btn-style(@arr.colors!.randint)");
    btn.setAttribute("style", newStyle);
  };
</script>
Enter fullscreen mode Exit fullscreen mode

clickable button: fscss

Click the button, and xfscss.process() recompiles @btn-style(@arr.colors!.randint) on demand, picking a fresh random color from the array each time. The style attribute gets swapped out, no rewritten CSS, no framework state, no manual color logic in JavaScript. FSCSS just runs again.

The part that trips: the array is still there

Once boot processes that button's style attribute, the visible result is just the compiled declarations. The @arr colors[...] line is gone from the DOM, cleaned up along with the rest of the FSCSS source.

But the array itself was registered during that processing pass, not just written to that one attribute. So it's still resolvable afterward. That's the whole reason the click handler above works: @arr.colors!.randint keeps returning a valid color long after the line that declared it has disappeared from the page.

It's a small detail, but it's what makes inline processing genuinely useful for interactivity rather than a one-shot trick.

module mixins work the same way

Since boot doesn't treat style attributes as a special case, anything you can call inside a <style> block, including mixins from imported modules, works inline too:

<div class="chart-line line-2" style="background: #E8A030; @st-chart-points(10, 20, 16, 15, 66, 50, 80, 54)"></div>
Enter fullscreen mode Exit fullscreen mode

That's an st-core chart mixin, called from an inline attribute, resolving exactly as it would from a stylesheet.

runtime.js or esm.js?

If you want this working automatically, runtime.js is the right entry point. It boots, processes every <style> block and style attribute on the page, and still exposes xfscss globally so you can call process() yourself afterward, exactly like the click handler above.

esm.js is a better fit when you want the compiler as a tool rather than something running against a live page, an FSCSS-to-CSS conversion utility, or a custom pipeline that decides what gets processed and when. It never touches the DOM unless you call reboot(), run(), or process() yourself.

Try it

<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.0/runtime.min.js" async></script>
Enter fullscreen mode Exit fullscreen mode

Resources:

API References fscss.devtem.org/api
Docs: fscss.devtem.org/docs
GitHub: github.com/Figsh/xfscss

Top comments (0)