Introduction to FSCSS @import
RECOMMENDEDThe @import method in FSCSS allows you to bring one .fscss file (or selected parts of it) into another. This gives your project a modular structure, where each file focuses on a single task (variables, mixins, components, utilities…).
Think of @import as connecting puzzle pieces: you make small, clean pieces of code and then combine them into a full stylesheet. This makes your styles easier to read, maintain, and reuse.
Modular Architecture
Split styles into logical, focused files
Reusability
Use modules across multiple projects
Team Collaboration
Multiple developers can work simultaneously
Selective Imports
Import only what you need with aliases
@import to organize your styles into logical groups (variables, mixins, buttons, layouts). This way you avoid one giant stylesheet that's hard to manage.
Modern Import Syntax (v1.1.16+ / v1.2.0)
Selective Import with Aliases
RecommendedThe preferred way to import is the selective form. You can pick exactly which exports you need and give them short aliases.
/* Import selected pieces from a module library and give them short names */
@import((
circle-progress as clp,
progress-range as pr,
progress-root as p-root
) from circle-progress)
/* Now use the aliases */
@p-root()
@clp(.progress-circle)
.p72 {
@pr(72)
}
This is the same pattern used by the official modules in fscss-modules.
impSel (pick / selective), impFrom (from), and procImp (full import).
You can disable any of them with exec.obj.block(f import), exec.obj.block(f import pick), or exec.obj.block(f import from).
Step 1 — Create Your Modules
Organize Code into Focused Files
@importStart by creating small, focused FSCSS files. For example:
_variables.fscss→ all colors, spacing, and sizes_mixins.fscss→ reusable functions like flex-center_buttons.fscss→ consistent button styles
_variables.fscss
/* Color Variables */
$primary: #3b82f6;
$secondary: #7c3aed;
$accent: #06b6d4;
$dark: #0f172a;
$light: #f8fafc;
/* Spacing Variables */
$spacing-sm: 0.5rem;
$spacing-md: 1rem;
$spacing-lg: 2rem;
/* Typography */
$font-main: 'Inter', sans-serif;
$font-heading: 'Inter', sans-serif;
_mixins.fscss
/* Flex Center Mixin */
str(flexCenter, "
display: flex;
justify-content: center;
align-items: center;
")
/* Card Style Mixin */
str(cardStyle, "
padding: $spacing-md!;
border-radius: 8px;
background: $light!;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
")
/* Responsive Breakpoint Mixin */
str(respond-to, "
@media (min-width: $breakpoint!) {
@content;
}
")
_buttons.fscss
/* Base Button */
.button {
padding: $spacing-sm! $spacing-md!;
border-radius: 4px;
font-weight: 600;
transition: all 0.3s ease;
border: none;
cursor: pointer;
}
/* Primary Button */
.btn-primary {
background: $primary!;
color: white;
&:hover {
background: darken($primary!, 10%);
}
}
/* Secondary Button */
.btn-secondary {
background: $secondary!;
color: white;
&:hover {
background: darken($secondary!, 10%);
}
}
Project Structure
Step 2 — Import Modules in Main File
Combine Modules with @import
@import(exec(...))Create a main.fscss file where you gather everything. You can still use the classic form:
/* Import Core Modules */
@import(exec(_variables.fscss))
@import(exec(_mixins.fscss))
@import(exec(_buttons.fscss))
/* Custom Styles */
body {
background: $light!;
color: $dark!;
font-family: $font-main!;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 $spacing-md!;
}
.card {
cardStyle
margin-bottom: $spacing-md!;
.card-title {
font-size: 1.5rem;
color: $primary!;
margin-bottom: $spacing-sm!;
}
}
.centered {
flexCenter
height: 100vh;
}
Or the modern selective form (preferred when the module exports multiple pieces):
@import((
flexCenter as center,
cardStyle as card
) from "_mixins.fscss")
.hero {
@center
height: 80vh;
}
.panel {
@card
}
This is a card with imported styles.
Step 3 — Link Main File in HTML
Connect FSCSS to Your HTML (v1.2.0)
HTML IntegrationFinally, link main.fscss inside your HTML page. With the new runtime entry point the compiler automatically processes everything.
fscss main.fscss main.css) so the page ships pure CSS.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FSCSS Modular Example</title>
<!-- Link your main FSCSS file -->
<link type="fscss" href="main.fscss">
<!-- New v1.2.0 + runtime (auto-runs) -->
<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.6/runtime.min.js" async></script>
</head>
<body>
<div class="container">
<div class="card">
<h2 class="card-title">Card Title</h2>
<p>This is a card with imported styles.</p>
<button class="button btn-primary">Primary Button</button>
<button class="button btn-secondary">Secondary Button</button>
</div>
</div>
</body>
</html>
Prefer full control? Use the ESM build instead:
<script type="module">
import xfscss from "https://cdn.jsdelivr.net/npm/fscss@1.2.6/esm.min.js";
await xfscss.reboot(); // processes all <link type="fscss"> and <style>
</script>
Advanced @import Usage
Powerful Import Patterns
Advanced FeaturesExplore advanced patterns for organizing and importing your FSCSS modules.
Nested Imports
You can import files inside other files for deep modularity.
/* components.fscss */
@import(exec(_buttons.fscss))
@import(exec(_cards.fscss))
@import(exec(_navigation.fscss))
Selective + Alias
Import only the pieces you need and rename them.
@import((
primaryBtn as btn,
secondaryBtn as btn2
) from "my-buttons.fscss")
.cta { @btn }
.alt { @btn2 }
With Events / Themes
Combine @import with events for dynamic loading.
@import(exec(_init themes))
div.star {
background: @event.theme(forest);
$box-size: 200px;
%2(width, height[: $box-size!;])
tr Shape: @event.shape(star);
}
Controlling the Import Pipeline
exec.obj.block for imports
You can selectively disable import processing stages when needed (debugging, special builds, etc.):
/* Skip all import handling */
exec.obj.block(f import);
/* Or skip only selective / from stages */
exec.obj.block(f import pick);
exec.obj.block(f import from);
All exec.obj.block(...) markers are stripped from the final CSS.
v1.2.6+ — Chained imports & dependency @define
How dependencies resolve
1.2.6From FSCSS 1.2.6, the import graph is resolved fully before your file finishes compiling.
- Chained imports resolve fully. If
cimportsbandbimportsa,b’s imports are resolved first so everything arrives inc’s output. Works for both*and named imports. - Relative paths resolve against the importing file.
./a.fscssinsidebis read relative tob, not the page or the process cwd. Same rule for local files and remote URL bases. - Named imports carry their dependencies. Importing
fooalso brings any@definethatfoocalls, and anything those call in turn. Carried dependencies keep their original names, even whenfoois imported with an alias. - Output is inserted as written.
$sequences in imported code ($&,$1, etc.) are not reinterpreted.
@import((foo as my-foo) from "./b.fscss")
/* Output includes:
- @define my-foo(...) (aliased export)
- @define blocks that foo depends on, under their ORIGINAL names
*/
@define of the same name already in the importing file. Prefer selective imports and unique prefixes in shared modules.
Rename with as — file ownership
Original name is undefined in this file
as fully renames the binding for the current file. No re-@define wrapper is required to pass names along in 1.2.6+: a file owns the names it imported; the next file can import those owned names.
@import((mirror as m) from fscss:micros)
@import((m as mirr) from "style.fscss")
@mirr(colors, indices) /* ✅ */
/* @m / @mirror ❌ undefined in app */
See also Modular system and @define.
Import forms (quick reference)
/* Named + alias */
@import((circle-progress as cp, progress-range as pr) from circle-progress)
/* Everything */
@import((*) from "animations.fscss")
/* Registry (no quotes) */
@import((*) from st-core@v2)
@import((mirror as m) from fscss:micros)
/* Remote (quotes) */
@import((btn) from "https://cdn.example/buttons.fscss")
/* Local */
@import((card) from "./components/card.fscss")
Libraries: /libraries · modules org: fscss-modules
Console warnings & CSS comments (v1.2.6+)
Duplicate, circular, and failed imports
The compiler logs to the console and often mirrors the same text as a CSS comment in the output so you can spot issues in exported CSS.
| Situation | Behavior | Typical message |
|---|---|---|
Same file imported with * more than once |
First wins; later skipped | /* Can't import <file> multiple times */ |
Circular graph (a → b → a) |
Cycle broken; no infinite loop | /* Circular import: <file> */ |
| Missing / failed fetch | Import skipped | /* Failed import: <file> */ |
| Name not exported | Error / no binding | not defined with @define in module |
Call original after as |
Undefined in this file | original name is not defined |
* as alias |
Invalid | Cannot assign * to alias |
/* a.fscss */
@import((*) from "./b.fscss")
/* b.fscss */
@import((*) from "./a.fscss")
/* Output may include: */
/* Circular import: ./a.fscss */
/* Console: FSCSS [@import] … circular / can't import <file> multiple times */
@import((*) from "./utils.fscss")
@import((*) from "./utils.fscss")
/* Second becomes a comment, e.g.: */
/* Can't import ./utils.fscss multiple times */
FSCSS [@import] …. Always check the compiled CSS for the matching /* … */ markers when debugging IDE or CLI output.
Compiler phases (register → extract → substitute)
- Registration —
@definestores blueprints (no CSS yet). - Extraction —
@importbinds names / aliases into this file (and resolves the dependency graph in 1.2.6+). - Substitution — calling
@name(args)fills@useand emits CSS.
Import stages can still be disabled with exec.obj.block(f import), exec.obj.block(f import pick), or exec.obj.block(f import from) when needed.
Benefits of Using @import
Why Modular Architecture Matters
Using @import provides significant advantages for both development and maintenance.
Organized Code
Split styles into logical files, reduce clutter, and find code faster
Flexible Architecture
Load only what you need, use selective imports, and reuse modules
Team Friendly
Multiple developers can work simultaneously with clear separation
Scalable
Easily add new features without breaking existing code
Ready to modularize?
Start with the official modules or build your own. The v1.2.6 runtime resolves chained imports, carries @define dependencies, and surfaces clear circular/duplicate messages.