The SYX token system is organized into 4 layers that provide scalability, maintainability, and consistency.
─── Application Layers ──────────────────────────────────────────────────────
Layer 1 — Primitives (--primitive-*) Raw values: colors, sizes, font scales,
[prefix] icon data-URIs, CSS filter values
Layer 2 — Semantic (--semantic-*) Contextual aliases: what a value MEANS,
[prefix] not what it IS
Layer 3 — Component (--component-*) Component-specific overrides, scoped
[prefix] to a single component
─── System Layers (cross-cutting) ───────────────────────────────────────────
Layout (--layout-*) Structural tokens: max-width, gaps, paddings.
Override per theme/breakpoint.
Reset (--reset-*) Base element defaults (html, body, h1–h6, selection),
wired to semantic tokens.
Icon (--icon-*) Semantic icon aliases that point to --primitive-icon-*.
Note: raw SVG data-URIs live in --primitive-icon-*;
--icon-* are convenient semantic names for them.
Theme (--theme-*) Architectural config tokens: focus shadow, global
border radius, thin border width. Override per theme.
Rule of thumb: Always consume the highest layer available for your context. Components use
--component-*→--semantic-*. Never reach directly into--primitive-*from a component (R01 rule enforced by the SYX validator).
Location: scss/abstracts/tokens/primitives/
Raw base values with no semantic context. These are the “atoms” of the system.
Also includes raw icon SVG data-URIs (--primitive-icon-*) and CSS filter
values for colorizing icons (--primitive-filter-*).
Naming: --primitive-{category}-{variant}-{modifier}
Examples:
--primitive-color-purple-500
--primitive-space-4
--primitive-font-size-2
--primitive-icon-arrow-default // SVG data-URI
--primitive-filter-error // CSS filter value
Location: scss/abstracts/tokens/semantic/
Contextual tokens that reference primitive tokens and carry meaning.
Naming: --semantic-{purpose}-{variant}-{state}
Examples:
--semantic-color-primary
--semantic-space-layout-md
--semantic-font-size-body
Location: scss/abstracts/tokens/components/
Component-specific tokens that reference semantic tokens.
Naming: --component-{name}-{property}-{variant}-{state}
Examples:
--component-button-primary-color
--component-form-field-padding-x
--component-table-border-width
.my-button {
// ✅ Correct: use component tokens
color: var(--component-button-primary-color);
padding: var(--component-button-padding-y) var(--component-button-padding-x);
border-radius: var(--component-button-border-radius);
&:hover {
color: var(--component-button-primary-color-hover);
}
}
Themes should only override primitive tokens. Semantic and component tokens will cascade automatically.
@mixin theme-example-02 {
// ✅ Correct: override primitives only
--primitive-space-base: 0.5rem;
--primitive-color-purple-500: hsl(248, 62%, 22%);
// ❌ Wrong: do not override semantic or component tokens
// --semantic-color-primary: ...
// --component-button-primary-color: ...
}
color: #ff0000)// 1. Define component tokens (if they don't exist)
:root {
--component-button-danger-text: var(--semantic-tone-error-text);
--component-button-danger-bg: transparent;
--component-button-danger-border: var(--semantic-tone-error-bg);
}
// 2. Use in the component
.button--danger {
color: var(--component-button-danger-color);
background: var(--component-button-danger-bg);
border: var(--component-button-border-width) solid
var(--component-button-danger-border);
}
// themes/_my-theme.scss
@mixin theme-my-theme {
// Change base measure
--primitive-space-base: 0.25rem;
// Change brand colors
--primitive-color-purple-500: hsl(280, 60%, 30%);
--primitive-color-pink-500: hsl(350, 100%, 65%);
// Change typography
--primitive-font-family-space-grotesk-regular: "Helvetica", Arial, sans-serif;
}
// 1. Add primitive
// primitives/_colors.scss
--primitive-color-info-500: hsl(200, 100%, 50%);
// 2. Add semantic alias
// semantic/_colors.scss
--semantic-tone-info-bg: var(--primitive-color-info-500);
// 3. Use in component
// components/_alerts.scss
--component-alert-info-bg: var(--semantic-tone-info-bg);
--primitive-color-{name}-{shade}--semantic-color-{purpose}--component-{name}-{property}-color--primitive-space-{number}--semantic-space-{context}-{size}--component-{name}-{property}--primitive-font-{property}-{value}--semantic-font-{purpose}--component-{name}-font-{property}--primitive-border-{property}-{value}--semantic-border-{property}-{size}--component-{name}-border-{property}--primitive-shadow-{size}--semantic-shadow-{purpose}--component-{name}-shadow-{state}✅ Scalability: Add new themes with minimal effort ✅ Maintainability: Global changes via primitive tokens only ✅ Consistency: Predictable naming across the system ✅ Self-documenting: Naming conveys purpose and context ✅ Collaboration: Designers and developers share the same vocabulary
SYX has two utility class systems with distinct purposes:
base/helpers/ — Theme-Aware HelpersLocation: scss/base/helpers/
Generated by: mixins with a $theme parameter (e.g., @include helper-backgrounds(example-01))
Class prefix: .syx-* — inside @layer syx.utilities
Classes generated per-theme compilation that use the active theme’s custom property tokens. Includes: spacers, font-sizes, dimensions, fonts, backgrounds, icons.
<!-- Class generated by helper-spacer(example-01) -->
<div class="syx-spacer-gap-t-1 syx-font-color-primary">...</div>
When to use: when you need classes that are bound to the active theme’s tokens (colors, icon sets, dimensions).
utilities/ — Global UtilitiesLocation: scss/utilities/
Generated by: plain CSS classes with no theme parameter
Class prefix: .syx-* — inside @layer syx.utilities
Theme-agnostic classes. Both systems share the .syx-* prefix and the @layer syx.utilities layer.
Includes: display, flexbox, spacing, text alignment, media, accessibility.
<!-- Class from utilities/display -->
<div class="syx-d-flex syx-justify-between">...</div>
When to use: for layout and composition utilities independent of any theme configuration.
| You need… | Use |
|---|---|
| Theme colors, icons, dimensions | base/helpers/ |
| Flexbox, display, spacing, alignment | utilities/ |
| Both | Both — they complement each other |
@layer implemented: syx.atoms, syx.molecules, syx.organisms, syx.utilities.syx-sr-only, .syx-skip-link, .syx-motion-safe added to _a11y.scsscolor-mix() for button hover tintsstyles-core.scss): production-ready, no documentation overhead. 138 KB without PurgeCSS, ~110 KB with PurgeCSS._template neutral theme (Section 3): buttons and forms have minimal visual identity with no SYX branding. Ideal base for new projects._directional.scss, _font.scss, _triangle.scss, _theme-config.scss.base/helpers/..helper-* class names renamed to .syx-*; all wrapped in @layer syx.utilities.layout/_index.scss renamed to layout/index.scss — consistent with the rest of the index files across the project.line-height bug fixed in 10 utility classes (_font-sizes.scss, _fonts.scss)* { color } selectors removed from _backgrounds.scssem across 5 files (21 occurrences)index.html audited to WCAG AAhome.html, docs.html, why-syx.html)SYX uses native CSS @layer to manage specificity without !important.
@layer syx.reset, syx.base, syx.tokens, syx.atoms, syx.molecules, syx.organisms, syx.utilities;
| Layer | Content | Wins over |
|---|---|---|
syx.reset |
Browser reset | — |
syx.base |
Element defaults, helpers | reset |
syx.tokens |
CSS custom property tokens | base |
syx.atoms |
Atomic components | tokens |
syx.molecules |
Composite components | atoms |
syx.organisms |
Complex UI sections | molecules |
syx.utilities |
Utility classes | everything |
Utility classes always win over components. This is by design.
<!-- .syx-d-none always hides the button, no !important needed -->
<button class="atom-btn atom-btn--primary syx-d-none">Hidden</button>
// ❌ Before (without @layer)
.syx-d-none {
display: none !important;
}
// ✅ Now (with @layer)
@layer syx.utilities {
.syx-d-none {
display: none; // Wins by position in the stack, not by !important
}
}
Note:
!importantis avoided throughout SYX by relying on@layer. The only accepted use is:
animation: none !importantinside@media (prefers-reduced-motion)— required by the specIf you find any other use of
!important, it’s likely a bug. Report it.