Mastors Framework
A utility-first SCSS design system. Three composable packages — design tokens, flexbox, and CSS Grid — built on a shared responsive engine.
@mastors/core
Foundation package
Design tokens, SCSS functions, mixins, utilities, responsive engine, accessibility, and theming.
@mastors/flexer
Flexbox utility system
Complete CSS Flexbox API — every property covered with utilities, responsive variants, and Sass mixins.
@mastors/gridder
CSS Grid utility system
Full 12-column CSS Grid system with named areas, layout presets, 4 mixins, and responsive variants.
Quick Install
npm install @mastors/corenpm install @mastors/flexernpm install @mastors/gridderEach package requires @mastors/core ≥1.0.0 and sass ≥1.80.0 as peer dependencies.
@mastors/core
The design system foundation — tokens, utilities, mixins, responsive engine
Overview
@mastors/core is a utility-first SCSS library providing design tokens, utility classes, mixins, functions, and a responsive engine. It is the foundation for every package in the Mastors design system and can be consumed standalone. All token-generated classes are driven by SCSS maps, and the library uses CSS custom properties so themes update at runtime without a rebuild.
Installation
Add the package via your package manager of choice.
npm
npm install @mastors/coreyarn
yarn add @mastors/corepnpm
pnpm add @mastors/coreImport & Usage
The main entry point compiles the full library: config → abstracts → variables → tokens → functions → mixins → base → themes → semantic → responsive → helpers → utilities → accessibility.
Full import — outputs all CSS
@use "@mastors/core";Selective import — tokens + mixins only, zero utility output
@use "@mastors/core/scss/tokens/color" as ct;
@use "@mastors/core/scss/tokens/spacing" as sp;
@use "@mastors/core/scss/mixins/breakpoint" as *;
.card {
padding: sp.spacing(4);
background: ct.color("primary", 50);
@include bp(md) {
padding: sp.spacing(8);
}
}Using the vars() function
@use "@mastors/core/scss/functions/vars" as *;
.btn {
background: vars(accent);
color: vars(accent-text);
padding: vars(spacing-2) vars(spacing-4);
border-radius: vars(radius-md);
box-shadow: vars(shadow-sm, none);
}Colors Token
6 palettes × 11 shades (50–950) plus white, black, and transparent. Each color is emitted as a CSS custom property: --mastors-color-{palette}-{shade}.
@use "@mastors/core/scss/tokens/color" as ct;
$blue: ct.color("primary", 500); // → #3b82f6
$green-50: ct.color("success", 50); // → #f0fdf4
$white: ct.color("white"); // → #fffprimary
success
warning
error
info
neutral
Spacing Token
A complete scale from 0 to 96 (0 → 24rem). Emitted as --mastors-spacing-{key}.
@use "@mastors/core/scss/tokens/spacing" as sp;
.btn { padding: sp.spacing(2) sp.spacing(4); }
// → padding: 0.5rem 1rem;| Key | rem Value | px | Key | rem Value | px |
|---|---|---|---|---|---|
| 0 | 0px | 0 | 8 | 2rem | 32px |
| px | 1px | 1px | 10 | 2.5rem | 40px |
| 0.5 | 0.125rem | 2px | 12 | 3rem | 48px |
| 1 | 0.25rem | 4px | 16 | 4rem | 64px |
| 1.5 | 0.375rem | 6px | 20 | 5rem | 80px |
| 2 | 0.5rem | 8px | 24 | 6rem | 96px |
| 3 | 0.75rem | 12px | 32 | 8rem | 128px |
| 4 | 1rem | 16px | 48 | 12rem | 192px |
| 5 | 1.25rem | 20px | 64 | 16rem | 256px |
| 6 | 1.5rem | 24px | 96 | 24rem | 384px |
Sizing Token
Width/height scale including fractional percentages, viewport units and keyword values. Emitted as --mastors-sizing-{key}.
@use "@mastors/core/scss/tokens/sizing" as sz;
.hero { width: sz.sizing("full"); height: sz.sizing("screen"); }
.card { width: sz.sizing("1/3"); max-width: sz.sizing(64); }| Key | Value | Key | Value |
|---|---|---|---|
| 0 | 0 | full | 100% |
| 1/2 | 50% | screen | 100vw |
| 1/3 | 33.333% | svw | 100svw |
| 2/3 | 66.667% | dvw | 100dvw |
| 1/4 | 25% | auto | auto |
| 3/4 | 75% | min | min-content |
| 1/5 | 20% | max | max-content |
| 4/5 | 80% | fit | fit-content |
Typography Tokens Token
Font sizes (xs–9xl), weights (thin–black), families (sans/serif/mono), line heights, and letter spacing. All emitted as CSS custom properties.
@use "@mastors/core/scss/tokens/typography" as ty;
h1 {
font-size: ty.font-size("4xl"); // 2.25rem
font-weight: ty.font-weight("bold"); // 700
line-height: ty.line-height("tight"); // 1.25
letter-spacing: ty.letter-spacing("tight"); // -0.025em
}
code { font-family: ty.font-family("mono"); }| Token | Key Examples | Values |
|---|---|---|
| font-size() | xs, sm, base, lg, xl, 2xl…9xl | 0.75rem … 8rem |
| font-weight() | thin, light, normal, medium, semibold, bold, extrabold, black | 100 … 900 |
| font-family() | sans, serif, mono | System stacks |
| line-height() | none, tight, snug, normal, relaxed, loose | 1 … 2 |
| letter-spacing() | tighter, tight, normal, wide, wider, widest | -0.05em … 0.1em |
Shadows Token
8 elevation steps: xs, sm, md, lg, xl, 2xl, inner, none. Emitted as --mastors-shadow-{key}.
@use "@mastors/core/scss/tokens/shadows" as sh;
.card { box-shadow: sh.shadow("md"); }
.modal { box-shadow: sh.shadow("2xl"); }
.input { box-shadow: sh.shadow("inner"); }xs
sm
md
lg
xl
2xl
inner
Radii Token
Border-radius scale from none (0) to full (9999px). Emitted as --mastors-radius-{key}.
@use "@mastors/core/scss/tokens/radii" as ra;
.btn { border-radius: ra.radius("md"); } // 0.375rem
.badge { border-radius: ra.radius("full"); } // 9999px
.card { border-radius: ra.radius("xl"); } // 0.75remOpacity Token
17-step opacity scale 0–100. Emitted as --mastors-opacity-{key}.
@use "@mastors/core/scss/tokens/opacity" as op;
.overlay { opacity: op.opacity(50); } // → 0.5
.disabled { opacity: op.opacity(30); } // → 0.3Z-Index Token
Named stacking layers for predictable layering. Emitted as --mastors-z-{key}.
@use "@mastors/core/scss/tokens/z-index" as zi;
.dropdown { z-index: zi.z("dropdown"); } // 100
.modal { z-index: zi.z("modal"); } // 400
.toast { z-index: zi.z("toast"); } // 500
.tooltip { z-index: zi.z("tooltip"); } // 600| Key | Value | Use Case |
|---|---|---|
| base | 0 | Default document flow |
| raised | 10 | Slightly elevated elements |
| dropdown | 100 | Dropdown menus |
| sticky | 200 | Sticky headers / sidebars |
| overlay | 300 | Backdrop overlays |
| modal | 400 | Modal dialogs |
| toast | 500 | Toast notifications |
| tooltip | 600 | Tooltips |
| max | 9999 | Escape hatch |
Transitions Token
Duration tokens (75ms–1000ms) and easing curves (linear, in, out, in-out, bounce). Emitted as --mastors-duration-{key} and --mastors-easing-{key}.
@use "@mastors/core/scss/tokens/transitions" as tr;
.btn {
transition: background-color tr.duration("150") tr.easing("in-out");
}
// Duration keys: 75, 100, 150, 200, 300, 500, 700, 1000
// Easing keys: linear, in, out, in-out, bounce
//
// tr.easing("out") → cubic-bezier(0, 0, 0.2, 1)
// tr.easing("bounce") → cubic-bezier(0.34, 1.56, 0.64, 1)Light & Dark Themes Theme
Themes are toggled via .dark or [data-theme="dark"] on any ancestor element. Themes redefine semantic custom properties — no class changes needed on individual components.
<!-- Class strategy (default) -->
<html class="dark">
<!-- or attribute strategy -->
<html data-theme="dark">
<!-- Toggle with JS -->
<script>
document.documentElement.classList.toggle('dark');
</script>// Override to media strategy (before @use):
$dark-mode-strategy: "media"; // default: "class"
@use "@mastors/core";Light theme
Dark theme
Semantic Layer Theme
Role-based SCSS variables mapping to CSS custom properties. Use these in components instead of raw token references — they update automatically when the theme changes.
@use "@mastors/core/scss/semantic/colors" as sc;
@use "@mastors/core/scss/semantic/spacing" as ss;
@use "@mastors/core/scss/semantic/typography" as st;
.card {
background: sc.$color-surface;
color: sc.$color-text;
border: 1px solid sc.$color-border;
padding: ss.$space-component;
font-family: st.$font-body;
// All $color-* variables resolve to var(--mastors-*)
// so they inherit the active theme at runtime
}| Variable | Custom Property | Role |
|---|---|---|
| $color-bg | --mastors-bg | Page background |
| $color-surface | --mastors-surface | Card / panel |
| $color-surface-raised | --mastors-surface-raised | Dropdowns, tooltips |
| $color-text | --mastors-text | Primary text |
| $color-text-muted | --mastors-text-muted | Secondary text |
| $color-text-subtle | --mastors-text-subtle | Placeholder / tertiary |
| $color-border | --mastors-border | Default border |
| $color-accent | --mastors-accent | Brand / primary action |
| $color-accent-hover | --mastors-accent-hover | Accent hover state |
| $space-inline | 0.25rem | Tight inline gap |
| $space-component | 1rem | Component padding |
| $space-section | 4rem | Between page sections |
Spacing Utilities UtilityResponsive
Margin, padding, and gap utilities generated from spacing tokens. Supports all directional variants, logical properties, and auto for margins.
<!-- Margin -->
<div class="m-4">margin: 1rem</div>
<div class="mx-auto">margin-inline: auto</div>
<div class="my-8">margin-block: 2rem</div>
<div class="mt-2 mb-6">margin-top + margin-bottom</div>
<div class="ms-4 me-4">margin-inline-start/end (logical)</div>
<!-- Padding -->
<div class="p-6">padding: 1.5rem</div>
<div class="px-4 py-2">padding-x + padding-y</div>
<div class="ps-4 pe-4">padding-inline-start/end</div>
<!-- Gap -->
<div class="flex gap-4">gap: 1rem</div>
<div class="grid gap-x-6 gap-y-3">column + row gap</div>All spacing keys: 0, px, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96 + auto (margins only).
Display UtilityResponsive
Display classes including responsive variants (e.g. md:flex, lg:hidden).
<div class="block"></div>
<div class="inline-block"></div>
<div class="inline"></div>
<div class="flex"></div>
<div class="inline-flex"></div>
<div class="grid"></div>
<div class="inline-grid"></div>
<div class="hidden"></div> <!-- display: none -->
<div class="contents"></div> <!-- display: contents -->
<!-- Responsive -->
<div class="hidden md:block">Shows from md up</div>
<div class="flex lg:hidden">Hidden from lg up</div>Position UtilityResponsive
Positioning classes + inset utilities for top/right/bottom/left values.
<div class="relative">
<div class="absolute top-0 right-0">top-right corner</div>
<div class="absolute inset-0">full overlay</div>
<div class="absolute inset-x-0 bottom-0">bottom bar</div>
</div>
<div class="sticky top-0">Sticky header</div>
<div class="fixed bottom-0 right-0">Floating btn</div>Inset keys: 0, auto, full (100%), 1/2 (50%)
Sizing Utility
Width and height utilities generated from sizing tokens. Includes min-width, max-width, min-height, max-height shortcuts.
<div class="w-full h-screen">Full width, screen height</div>
<div class="w-1/2 h-32">50% width, 8rem height</div>
<div class="w-fit">Width: fit-content</div>
<!-- Min / Max -->
<div class="min-w-0 max-w-prose">Prose width (65ch)</div>
<div class="min-h-screen">Min 100vh height</div>
<div class="min-h-svh">Min 100svh (small viewport)</div>
<div class="min-h-dvh">Min 100dvh (dynamic viewport)</div>Typography Utilities UtilityResponsive
Text size, weight, family, alignment, leading, tracking, decoration, transform, and more.
<!-- Size -->
<p class="text-xs"> <p class="text-sm"> <p class="text-base">
<p class="text-lg"> <p class="text-xl"> <p class="text-2xl"> … <p class="text-9xl">
<!-- Weight -->
<p class="font-thin"> <p class="font-light"> <p class="font-normal">
<p class="font-medium"> <p class="font-semibold"> <p class="font-bold">
<p class="font-extrabold"> <p class="font-black">
<!-- Family -->
<p class="font-sans"> <p class="font-serif"> <p class="font-mono">
<!-- Alignment (responsive) -->
<p class="text-left"> <p class="text-center"> <p class="text-right">
<p class="md:text-center">
<!-- Line height -->
<p class="leading-none"> <p class="leading-tight"> <p class="leading-normal">
<p class="leading-relaxed"> <p class="leading-loose">
<!-- Letter spacing -->
<p class="tracking-tight"> <p class="tracking-normal"> <p class="tracking-wide">
<p class="tracking-widest">
<!-- Transform -->
<p class="uppercase"> <p class="lowercase"> <p class="capitalize">
<!-- Decoration -->
<p class="underline"> <p class="line-through"> <p class="no-underline">
<p class="decoration-wavy decoration-2">
<!-- Misc -->
<p class="italic"> <p class="antialiased"> <p class="text-ellipsis">
<p class="whitespace-nowrap"> <p class="break-words">text-4xl font-bold
text-base — The quick brown fox
text-xs — The quick brown fox
decoration-wavy text-blue
TRACKING-WIDEST UPPERCASE
Color Utilities Utility
Text color, background color, and border color classes for both semantic and primitive palettes.
<!-- Semantic text colors -->
<p class="text-default">Default text</p>
<p class="text-muted">Muted text</p>
<p class="text-subtle">Subtle text</p>
<p class="text-accent">Accent text</p>
<p class="text-inverse">Inverse text</p>
<!-- Primitive text colors -->
<p class="text-primary-600">Primary 600</p>
<p class="text-success-500">Success 500</p>
<p class="text-error-500">Error 500</p>
<p class="text-white"> <p class="text-black">
<!-- Semantic backgrounds -->
<div class="bg-default"> <div class="bg-subtle">
<div class="bg-surface"> <div class="bg-accent">
<!-- Primitive backgrounds -->
<div class="bg-primary-50"> <div class="bg-neutral-100">
<div class="bg-warning-200"> <div class="bg-white">
<div class="bg-transparent">Borders Utility
Border width, style, color, and radius classes.
<!-- Width -->
<div class="border">1px</div> <div class="border-2">2px</div>
<div class="border-4">4px</div> <div class="border-0">no border</div>
<div class="border-t">top only</div> <div class="border-b">bottom only</div>
<!-- Style -->
<div class="border border-dashed">dashed</div>
<div class="border border-dotted">dotted</div>
<!-- Color -->
<div class="border border-default">semantic border</div>
<div class="border border-primary-300">primitive color</div>
<div class="border border-transparent">transparent</div>
<!-- Radius -->
<div class="rounded-none"> <div class="rounded-sm"> <div class="rounded">
<div class="rounded-md"> <div class="rounded-lg"> <div class="rounded-xl">
<div class="rounded-2xl"> <div class="rounded-3xl"> <div class="rounded-full">
<!-- Directional radius -->
<div class="rounded-t-lg"> <!-- top corners -->
<div class="rounded-b-xl"> <!-- bottom corners -->
<div class="rounded-l-full"> <!-- left corners -->Shadow Utilities Utility
<div class="shadow-xs">Extra small shadow</div>
<div class="shadow-sm">Small shadow</div>
<div class="shadow">Default (md) shadow</div>
<div class="shadow-lg">Large shadow</div>
<div class="shadow-xl">XL shadow</div>
<div class="shadow-2xl">2XL shadow</div>
<div class="shadow-inner">Inset shadow</div>
<div class="shadow-none">No shadow</div>Opacity Utilities Utility
<div class="opacity-0"> <!-- 0 -->
<div class="opacity-5"> <!-- 0.05 -->
<div class="opacity-10"> <!-- 0.1 -->
<div class="opacity-25"> <!-- 0.25 -->
<div class="opacity-50"> <!-- 0.5 -->
<div class="opacity-75"> <!-- 0.75 -->
<div class="opacity-90"> <!-- 0.9 -->
<div class="opacity-100"> <!-- 1 -->Transform Utility
Translate, rotate, scale, and transform-origin classes. Use .transform-gpu to promote to a composite layer.
<!-- Translate -->
<div class="translate-x-4"> <!-- translateX(1rem) -->
<div class="translate-y-2"> <!-- translateY(0.5rem) -->
<div class="-translate-y-1"> <!-- translateY(-0.25rem) -->
<div class="translate-x-full"> <!-- translateX(100%) -->
<!-- Rotate -->
<div class="rotate-45"> <div class="rotate-90">
<div class="rotate-180"> <div class="-rotate-45">
<!-- Scale -->
<div class="scale-0"> <div class="scale-50"> <div class="scale-100">
<div class="scale-105"> <div class="scale-110"> <div class="scale-x-75">
<!-- Origin -->
<div class="origin-center"> <div class="origin-top"> <div class="origin-bottom-right">
<!-- GPU -->
<div class="transform-gpu"> <div class="transform-none">rotate-45
scale-125
translate-x-4
Animation & Transitions Utility
Built-in keyframe animations (spin, ping, pulse, bounce, fade-in, fade-out, slide-up, slide-down, scale-in) plus transition property, duration, easing, and delay utilities.
<!-- Animations -->
<div class="animate-spin">Spinner</div>
<div class="animate-ping">Ping dot</div>
<div class="animate-pulse">Pulsing skeleton</div>
<div class="animate-bounce">Bouncing indicator</div>
<div class="animate-fade-in">Fade in on mount</div>
<div class="animate-fade-out">Fade out</div>
<div class="animate-slide-up">Slide up</div>
<div class="animate-slide-down">Slide down</div>
<div class="animate-scale-in">Scale in</div>
<div class="animate-none">No animation</div>
<!-- Transitions -->
<div class="transition">All common properties</div>
<div class="transition-colors">Colors only</div>
<div class="transition-opacity">Opacity only</div>
<div class="transition-transform">Transform only</div>
<div class="transition-none">Disable</div>
<!-- Duration -->
<div class="duration-75"> <div class="duration-150"> <div class="duration-300">
<div class="duration-700"> <div class="duration-1000">
<!-- Easing -->
<div class="ease-linear"> <div class="ease-in"> <div class="ease-out">
<div class="ease-in-out"> <div class="ease-bounce">
<!-- Delay -->
<div class="delay-150"> <div class="delay-300"> <div class="delay-700">
<!-- Fill mode / Play state -->
<div class="fill-forwards"> <div class="fill-both">
<div class="animation-paused"> <div class="animation-running">
<div class="animate-repeat-infinite"> <div class="animate-repeat-1">spin
pulse
bounce
Cursor Utility
<div class="cursor-auto">auto</div>
<div class="cursor-default">default arrow</div>
<div class="cursor-pointer">hand pointer</div>
<div class="cursor-wait">wait spinner</div>
<div class="cursor-text">I-beam</div>
<div class="cursor-move">move</div>
<div class="cursor-not-allowed">blocked</div>
<div class="cursor-grab">grab hand</div>
<div class="cursor-grabbing">grabbing</div>
<div class="cursor-zoom-in">zoom in</div>
<div class="cursor-crosshair">crosshair</div>
<div class="cursor-none">hidden cursor</div>Interaction Utility
User-select, resize, scroll behavior, scroll snap, touch action, pointer events, and state-variant pseudo-class utilities (hover:, focus:, disabled:).
<!-- User select -->
<div class="select-none">Cannot select</div>
<div class="select-text">Can select text</div>
<div class="select-all">Select all on click</div>
<!-- Resize -->
<textarea class="resize-none">No resize</textarea>
<textarea class="resize-y">Vertical resize</textarea>
<textarea class="resize">Both directions</textarea>
<!-- Scroll snap -->
<div class="snap-x snap-mandatory overflow-x-auto">
<div class="snap-start">Snap item 1</div>
<div class="snap-center">Snap item 2</div>
</div>
<!-- Touch -->
<div class="touch-pan-x">Horizontal pan only</div>
<div class="touch-manipulation">Fast tap, no zoom</div>
<!-- Pointer events -->
<div class="pointer-events-none">Click-through</div>
<div class="pointer-events-auto">Default</div>
<!-- State variants -->
<button class="hover:bg-accent hover:scale-105">Hover effects</button>
<button class="focus:ring focus:ring-2">Focus ring</button>
<button class="disabled:opacity-50 disabled:cursor-not-allowed">Disabled</button>Layout UtilityResponsive
Aspect ratio, object-fit, object-position, float, clear, isolation, mix-blend-mode, background blend, appearance, and will-change.
<!-- Aspect ratio -->
<div class="aspect-auto"> <div class="aspect-square">
<div class="aspect-video"> <!-- 16/9 -->
<div class="aspect-4-3"> <div class="aspect-21-9">
<div class="aspect-golden"> <!-- 1.618 -->
<!-- Object fit -->
<img class="object-cover"> <img class="object-contain">
<img class="object-fill"> <img class="object-scale-down">
<!-- Object position -->
<img class="object-center"> <img class="object-top">
<img class="object-bottom"> <img class="object-left">
<!-- Float -->
<div class="float-left"> <div class="float-right"> <div class="float-none">
<!-- Overflow -->
<div class="overflow-auto"> <div class="overflow-hidden">
<div class="overflow-scroll"> <div class="overflow-visible">
<div class="overflow-x-auto overflow-y-hidden">Horizontal scroll</div>
<!-- Misc -->
<div class="isolate"> <!-- isolation: isolate -->
<div class="mix-blend-multiply"> <!-- mix-blend-mode -->
<select class="appearance-none"> <!-- custom select -->
<div class="will-change-transform"> <!-- GPU hint -->Helpers
Pre-built helper classes for text truncation, line clamping, aspect ratios, clearfix, and visually-hidden content.
Truncate & Line Clamp
<p class="truncate">Single line truncation with ellipsis...</p>
<p class="line-clamp-1">Clamp to 1 line</p>
<p class="line-clamp-2">Clamp to 2 lines</p>
<p class="line-clamp-3">Clamp to 3 lines — max 3 visible</p>
<p class="line-clamp-6">Clamp to 6 lines</p>
<p class="break-words">Break long overflow words</p>
<p class="break-all">Break at any character</p>This is a very long sentence that should be truncated with an ellipsis at the end when it overflows its container.
Ratio Helpers & Clearfix
<div class="ratio-square">1:1 ratio</div>
<div class="ratio-video">16:9 ratio</div>
<div class="ratio-portrait">3:4 ratio</div>
<div class="ratio-wide">21:9 ultra-wide</div>
<div class="ratio-golden">Golden ratio (1.618)</div>
<!-- Clears floated children with ::after -->
<div class="clearfix">
<img class="float-left" src="..." />
<p>Text alongside float</p>
</div>Functions
Pure Sass functions — zero CSS output when imported alone. Use via @use "@mastors/core/scss/functions/...".
rem() & em() Unit Conversion
@use "@mastors/core/scss/functions/rem" as *;
@use "@mastors/core/scss/functions/em" as *;
.heading { font-size: rem(32px); } // → 2rem
.media { max-width: em(768px, 16px); } // → 48emColor Functions
@use "@mastors/core/scss/functions/color" as *;
// tint($color, $pct) — mix with white
$light: tint(#3b82f6, 40%);
// shade($color, $pct) — mix with black
$dark: shade(#3b82f6, 30%);
// alpha($color, $alpha) — set alpha
$semi: alpha(#3b82f6, 0.5);
// contrast($bg) — returns black or white for best contrast
$text: contrast(#3b82f6); // → #ffffff
// palette($name, $shade) — shorthand accessor
$c: palette("primary", 500);
// rgb-color($name, $shade, $opacity) — with optional alpha
$c: rgb-color("primary", 500, 0.6);
// color-ramp($base, $steps, $dir) — tint/shade ramp
$ramp: color-ramp(#3b82f6, 5, "tint");Math Functions
@use "@mastors/core/scss/functions/math" as *;
// fluid($min, $max, $min-vw, $max-vw) — clamp() expression
font-size: fluid(1rem, 2rem);
// → clamp(1rem, calc(…vw + …), 2rem)
// clamp-value($min, $val, $max)
font-size: clamp-value(0.875rem, 4vw, 2rem);
// strip-unit(16px) → 16
$n: strip-unit(16px);
// round-to(3.14159, 2) → 3.14
$r: round-to(3.14159);
// lerp($a, $b, $t) — linear interpolation
$v: lerp(0, 100px, 0.5); // → 50pxvars() — Token Reference Function
@use "@mastors/core/scss/functions/vars" as *;
// Simple token reference (no fallback)
.card {
background: vars(surface); // var(--mastors-surface)
color: vars(text); // var(--mastors-text)
border: 1px solid vars(border); // var(--mastors-border)
}
// With CSS fallback
.badge {
background: vars(accent-subtle, #eff6ff); // var(--mastors-accent-subtle, #eff6ff)
}
// Path-based string accessor
@use "@mastors/core/scss/functions/string" as sf;
color: sf.vars(color, primary, 500); // var(--mastors-color-primary-500)
gap: sf.vars(spacing, 4); // var(--mastors-spacing-4)Map Helpers
@use "@mastors/core/scss/functions/map-helpers" as *;
$nested: ("colors": ("blue": #3b82f6));
$blue: map-deep-get($nested, "colors", "blue"); // → #3b82f6
$merged: map-collect($map-a, $map-b, $map-c); // shallow mergeMixins
Breakpoint Mixin Responsive
@use "@mastors/core/scss/mixins/breakpoint" as *;
.sidebar {
display: none;
@include bp(sm) { display: block; } // min-width: 640px
@include bp(md) { width: 240px; } // min-width: 768px
@include bp(lg) { width: 300px; } // min-width: 1024px
@include bp(2xl) { width: 360px; } // min-width: 1536px
}
// Aliases — all equivalent:
@include respond-to(md) { ... }
@include breakpoint-up(md) { ... }
// Below a breakpoint (max-width):
@include breakpoint-down(lg) { ... }
// Available keys: xs(0) sm(640px) md(768px) lg(1024px) xl(1280px) 2xl(1536px)Container Mixin
@use "@mastors/core/scss/mixins/container" as *;
.page-wrapper {
@include container;
// width: 100%; margin-inline: auto; padding-inline: 1rem;
// max-width: 640px @sm, 768px @md, 1024px @lg, 1280px @xl, 1400px @2xl
}Elevation Mixin
@use "@mastors/core/scss/mixins/elevation" as *;
.card { @include elevation("md"); } // box-shadow: md token
.nav { @include elevation("lg"); } // box-shadow: lg token
// Keys: xs sm md lg xl 2xl inner noneTransition Mixin
@use "@mastors/core/scss/mixins/transition" as *;
.btn {
// transition($props, $duration, $easing)
@include transition((background-color, color), "150", "in-out");
// → transition: background-color 150ms cubic-bezier(0.4,0,0.2,1),
// color 150ms cubic-bezier(0.4,0,0.2,1);
}Theme Mixin
@use "@mastors/core/scss/mixins/theme" as *;
.card {
background: #fff;
@include dark-mode {
background: #1f2937;
color: #f9fafb;
}
@include light-mode {
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
}
// Named theme (data-theme="ocean")
@include theme("ocean") {
background: #083344;
color: #ecfeff;
}
}Pseudo Mixin
@use "@mastors/core/scss/mixins/pseudo" as *;
.badge::before {
@include pseudo($display: inline-block, $pos: relative, $content: "");
width: 8px; height: 8px;
border-radius: 50%;
background: currentColor;
}Breakpoints Engine
Mobile-first breakpoints used by the responsive engine to generate prefixed utility variants. xs is the base (no prefix).
<!-- Pattern: {bp}:{utility} -->
<div class="hidden sm:block"> Shown sm+</div>
<div class="block md:hidden"> Hidden md+</div>
<div class="flex-col lg:flex-row"> Row from lg</div>
<div class="text-sm xl:text-base"> Bigger on xl</div>| Key | min-width | Breakpoint |
|---|---|---|
| xs | 0px | All screens (no prefix) |
| sm | 640px | Large phones + |
| md | 768px | Tablets + |
| lg | 1024px | Laptops + |
| xl | 1280px | Desktops + |
| 2xl | 1536px | Wide screens + |
responsive: true in their config generate breakpoint variants. Currently enabled: display, position, text-align, float, clear.
Fluid Typography Responsive
Uses clamp() to scale font sizes smoothly between two viewport widths. No media queries needed.
@use "@mastors/core/scss/responsive/fluid-type" as ft;
// Apply fluid font-size to an element
.hero-title {
@include ft.apply-fluid-type(2rem, 4rem);
// → font-size: clamp(2rem, calc(…vw + …), 4rem);
}
// Custom viewport range
.headline {
@include ft.apply-fluid-type(1.5rem, 3rem, 480px, 1400px);
}
// Function — use inside any property value
.lead {
font-size: ft.fluid-type(1rem, 1.5rem);
}
// Pre-built fluid heading scale (opt-in)
// Scales h1–h6 + p fluidly across 320px–1280px
@include ft.fluid-scale();
// h1: clamp(2rem, …, 3.75rem)
// h2: clamp(1.5rem, …, 3rem)
// h3: clamp(1.25rem, …, 2.25rem)
// h4–h6, p: proportionally smallerContainer Queries Responsive
CSS container query helpers. Supports inline-size and size containment types.
<!-- Create containment context -->
<div class="cq-inline"> <!-- container-type: inline-size -->
<div class="cq-size"> <!-- container-type: size -->
<div data-container> <!-- shorthand alias -->@use "@mastors/core/scss/responsive/container-queries" as cq;
.card {
// When the container is at least 40rem wide
@include cq.cq(40rem) {
display: grid;
grid-template-columns: 1fr 2fr;
}
// Named container query
@include cq.cq(30rem, "sidebar") {
font-size: 0.875rem;
}
}A11y Utilities
Built-in accessibility: focus rings, reduced motion, screen-reader utilities, and print helpers.
Screen Reader Utilities
<!-- Visually hidden but accessible to screen readers -->
<span class="sr-only">Menu (label)</span>
<!-- Undo sr-only — make visible again -->
<span class="not-sr-only">Now visible</span>
<!-- Legacy aliases (all equivalent to sr-only) -->
<span class="visually-hidden">Hidden visually</span>
<span class="vh">Shorthand alias</span>
<!-- Shown when focused (skip links) -->
<a class="visually-hidden-focusable" href="#main">
Skip to main content
</a>Focus Ring
Automatically applied to :focus-visible. Mouse users see no ring.
/* Auto-applied by accessibility/_focus.scss */
:focus-visible {
outline: 2px solid var(--mastors-color-primary-500, #3b82f6);
outline-offset: 2px;
border-radius: 2px;
}Reduced Motion
/* Auto-applied — no class needed */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}Print Utilities
<nav class="print:hidden">Navigation</nav>
<div class="screen:hidden">Print-only watermark</div>
<section class="print:break-inside-avoid">...</section>
<div class="print:break-before">New page before</div>
<p class="print:text-black print:bg-white">Print-safe</p>Reset & Root
The base layer applies an opinionated modern CSS reset and emits all token-based CSS custom properties on :root.
/* box-sizing: border-box on everything */
*, *::before, *::after { box-sizing: border-box; }
/* Zero margin/padding everywhere */
* { margin: 0; padding: 0; }
/* Smooth scroll + tab-size */
html { text-size-adjust: 100%; tab-size: 4; scroll-behavior: smooth; }
/* Font smoothing */
body { -webkit-font-smoothing: antialiased; }
/* Block images, max 100% */
img, picture, video, canvas, svg { display: block; max-width: 100%; }
/* Form elements inherit font */
input, button, textarea, select { font: inherit; }
/* Break long words */
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
/* Removed list styles */
ol, ul { list-style: none; }
/* Links inherit color */
a { color: inherit; text-decoration: inherit; }
/* Cursor on interactive */
button, [role="button"] { cursor: pointer; }:root {
/* Colors — --mastors-color-primary-50 … -950 × 6 palettes */
--mastors-color-primary-500: #3b82f6;
--mastors-color-success-500: #22c55e;
/* Spacing */
--mastors-spacing-4: 1rem;
/* Typography */
--mastors-font-size-xl: 1.25rem;
--mastors-font-weight-bold: 700;
/* Radii */
--mastors-radius-md: 0.375rem;
/* Shadows */
--mastors-shadow-md: 0 4px 6px -1px rgb(0 0 0/10%),...;
/* Transitions */
--mastors-duration-300: 300ms;
--mastors-easing-in-out: cubic-bezier(0.4, 0, 0.2, 1);
/* Z-index */
--mastors-z-modal: 400;
/* Opacity */
--mastors-opacity-50: 0.5;
}@mastors/flexer
Complete CSS Flexbox utility system — every property, responsive, with Sass mixins
Overview
@mastors/flexer is a purpose-built SCSS package that provides a complete, production-ready flexbox utility class system. Every CSS flexbox property — from display and flex-direction through to place-self and order — is covered with utility classes, responsive breakpoint variants, and composable Sass mixins. It consumes @mastors/core for its token system and responsive engine.
sm:flex-col, lg:justify-between, etc.
Installation
Requires @mastors/core ≥ 1.0.0 and sass ≥ 1.80.0 as peer dependencies.
npm
npm install @mastors/flexerpnpm
pnpm add @mastors/flexeryarn
yarn add @mastors/flexer// Full import — outputs all flexbox utility classes
@use "@mastors/core";
@use "@mastors/flexer";
// Sass mixins only (no CSS output)
@use "@mastors/flexer/scss/mixins/flex-container" as *;
@use "@mastors/flexer/scss/mixins/flex-item" as *;
@use "@mastors/flexer/scss/mixins/flex-center" as *;Flex Display DisplayResponsive
Establishes a flex formatting context. Use flex for block-level and inline-flex for inline-level containers.
| Class | CSS output | When to use |
|---|---|---|
| .flex | display: flex | Block-level flex container — full parent width |
| .inline-flex | display: inline-flex | Inline flex container — wraps content tightly |
<div class="flex gap-3">
<div>Item 1</div><div>Item 2</div><div>Item 3</div>
</div>
<span class="inline-flex items-center gap-2">
<i class="fa-solid fa-star"></i>
<span>Inline badge</span>
</span>.flex — row by default
.inline-flex — hugs content
Inline flex badgeFlex Direction ContainerResponsive
Controls the main axis — the direction items are placed in a flex container.
| Class | CSS output | Description |
|---|---|---|
| .flex-row | flex-direction: row | Left to right (default). Horizontal main axis. |
| .flex-row-reverse | flex-direction: row-reverse | Right to left. Reverse horizontal order. |
| .flex-col | flex-direction: column | Top to bottom. Vertical main axis. |
| .flex-col-reverse | flex-direction: column-reverse | Bottom to top. Reverse vertical order. |
<div class="flex flex-row gap-3">...</div>
<div class="flex flex-row-reverse gap-3">...</div>
<div class="flex flex-col gap-3">...</div>
<div class="flex flex-col-reverse gap-3">...</div>
<!-- Responsive: column on mobile, row on md+ -->
<div class="flex flex-col md:flex-row gap-4">
<aside>Sidebar</aside>
<main>Content</main>
</div>flex-row
flex-row-reverse
flex-col
flex-col-reverse
Flex Wrap ContainerResponsive
Controls whether flex items wrap to the next line when they overflow the container's main axis.
| Class | CSS output | Description |
|---|---|---|
| .flex-wrap | flex-wrap: wrap | Items wrap to next row/column on overflow. |
| .flex-wrap-reverse | flex-wrap: wrap-reverse | Items wrap, but wrapped lines appear before the first line. |
| .flex-nowrap | flex-wrap: nowrap | No wrapping. Items stay on one line (browser default). |
<!-- Items wrap naturally -->
<div class="flex flex-wrap gap-2">
<div>Alpha</div><div>Beta</div><div>Gamma</div><div>Delta</div>
</div>
<!-- Force single line (scroll) -->
<div class="flex flex-nowrap overflow-x-auto gap-2">...</div>flex-wrap
flex-nowrap
Flex Flow ContainerResponsive
Shorthand that sets both flex-direction and flex-wrap in a single class.
| Class | CSS output |
|---|---|
| .flex-flow-row-wrap | flex-flow: row wrap |
| .flex-flow-row-nowrap | flex-flow: row nowrap |
| .flex-flow-row-wrap-reverse | flex-flow: row wrap-reverse |
| .flex-flow-col-wrap | flex-flow: column wrap |
| .flex-flow-col-nowrap | flex-flow: column nowrap |
| .flex-flow-col-wrap-reverse | flex-flow: column wrap-reverse |
<!-- Column direction with wrapping -->
<div class="flex flex-flow-col-wrap gap-3" style="height:8rem">
<div>A</div><div>B</div><div>C</div><div>D</div>
</div>Flex Grow Item
Controls how much a flex item grows to fill available free space relative to its siblings.
| Class | CSS output | Description |
|---|---|---|
| .grow | flex-grow: 1 | Item grows to fill all available space. Shares evenly with other .grow items. |
| .grow-0 | flex-grow: 0 | Item does not grow beyond its natural or basis size. |
<!-- Middle item grows to fill remaining space -->
<div class="flex gap-3">
<div class="grow-0">Fixed</div>
<div class="grow">Grows to fill space</div>
<div class="grow-0">Fixed</div>
</div>grow-0 / grow / grow-0
Flex Shrink Item
Controls how much a flex item shrinks when the container doesn't have enough space.
| Class | CSS output | Description |
|---|---|---|
| .shrink | flex-shrink: 1 | Item shrinks proportionally when container is too narrow (default). |
| .shrink-0 | flex-shrink: 0 | Item never shrinks — preserves its full width even when space is tight. |
<!-- Logo never shrinks; nav items share remaining space -->
<header class="flex items-center gap-4">
<img class="shrink-0 w-32" src="logo.svg" />
<nav class="flex gap-4 shrink">...</nav>
<button class="shrink-0">CTA</button>
</header>Flex Basis Item
Sets the initial main size of a flex item before free space is distributed.
| Class | Value | Class | Value |
|---|---|---|---|
| .basis-auto | auto | .basis-1/2 | 50% |
| .basis-full | 100% | .basis-1/3 | 33.33% |
| .basis-0 | 0px | .basis-2/3 | 66.67% |
| .basis-1/4 | 25% | .basis-3/4 | 75% |
| .basis-1/5 | 20% | .basis-1/6 | 16.67% |
| .basis-1/12 | 8.33% | .basis-16 – .basis-96 | 4rem – 24rem |
<!-- Sidebar 1/4 + Main 3/4 layout -->
<div class="flex flex-wrap gap-4">
<aside class="basis-1/4">Sidebar</aside>
<main class="basis-3/4">Content</main>
</div>
<!-- Three equal columns -->
<div class="flex flex-wrap gap-4">
<div class="basis-1/3">Col 1</div>
<div class="basis-1/3">Col 2</div>
<div class="basis-1/3">Col 3</div>
</div>basis-1/3 × 3
Flex Shorthand Item
Combines flex-grow, flex-shrink, and flex-basis into a single class.
| Class | CSS output | Behaviour |
|---|---|---|
| .flex-1 | flex: 1 1 0% | Grows, shrinks, starts from zero basis. Everyday equal-width items. |
| .flex-auto | flex: 1 1 auto | Grows and shrinks from the item's natural size. |
| .flex-initial | flex: 0 1 auto | Won't grow, but will shrink if needed (browser default). |
| .flex-none | flex: none | Completely rigid — won't grow or shrink. |
<!-- Three equal-width columns from zero basis -->
<div class="flex gap-4">
<div class="flex-1">Column</div>
<div class="flex-1">Column</div>
<div class="flex-1">Column</div>
</div>
<!-- Fixed avatar + growing text -->
<div class="flex items-center gap-3">
<img class="flex-none w-10 h-10 rounded-full" src="..." />
<div class="flex-1 min-w-0">
<p class="truncate">Username</p>
</div>
</div>flex-1 — equal columns from zero
flex-none + flex-1 + flex-none
Justify Content ContainerResponsive
Aligns flex items along the main axis (horizontal in flex-row, vertical in flex-col).
| Class | CSS output | Description |
|---|---|---|
| .justify-start | justify-content: flex-start | Pack items to start (default) |
| .justify-end | justify-content: flex-end | Pack items to end |
| .justify-center | justify-content: center | Center items |
| .justify-between | justify-content: space-between | First at start, last at end, equal space between |
| .justify-around | justify-content: space-around | Equal space around each item |
| .justify-evenly | justify-content: space-evenly | Equal space between and around every item |
| .justify-stretch | justify-content: stretch | Items stretch to fill available space |
<div class="flex justify-start gap-2">...</div>
<div class="flex justify-center gap-2">...</div>
<div class="flex justify-end gap-2">...</div>
<div class="flex justify-between">...</div>
<div class="flex justify-around">...</div>
<div class="flex justify-evenly">...</div>
<!-- Responsive -->
<div class="flex justify-center lg:justify-between">...</div>justify-start
justify-center
justify-end
justify-between
justify-evenly
Align Items ContainerResponsive
Aligns all flex items along the cross axis within a single flex line.
| Class | CSS output | Description |
|---|---|---|
| .items-start | align-items: flex-start | Items align to the start of the cross axis |
| .items-end | align-items: flex-end | Items align to the end of the cross axis |
| .items-center | align-items: center | Items center on the cross axis |
| .items-stretch | align-items: stretch | Items stretch to fill cross-axis size (default) |
| .items-baseline | align-items: baseline | Items align by their text baselines |
<!-- Vertically center items -->
<div class="flex items-center gap-4 h-24">
<div>Short</div>
<div class="h-16">Tall</div>
<div class="h-8">Medium</div>
</div>
<!-- Baseline alignment -->
<div class="flex items-baseline gap-3">
<span class="text-3xl font-bold">Big</span>
<span class="text-sm">aligned by baseline</span>
</div>items-start
items-center
items-end
items-stretch
items-baseline
Align Self ItemResponsive
Overrides the container's align-items for a single flex item on the cross axis.
| Class | CSS output |
|---|---|
| .self-auto | align-self: auto |
| .self-start | align-self: flex-start |
| .self-end | align-self: flex-end |
| .self-center | align-self: center |
| .self-stretch | align-self: stretch |
| .self-baseline | align-self: baseline |
<div class="flex items-start gap-4 h-32">
<div>Top</div>
<div class="self-center">Middle</div>
<div class="self-end">Bottom</div>
<div class="self-stretch">Full height</div>
</div>Align Content ContainerResponsive
Aligns flex lines along the cross axis when there are multiple wrapped lines. Has no effect on single-line containers.
| Class | CSS output |
|---|---|
| .content-normal | align-content: normal |
| .content-start | align-content: flex-start |
| .content-end | align-content: flex-end |
| .content-center | align-content: center |
| .content-between | align-content: space-between |
| .content-around | align-content: space-around |
| .content-evenly | align-content: space-evenly |
| .content-stretch | align-content: stretch |
| .content-baseline | align-content: baseline |
<!-- Must have flex-wrap + fixed height to see effect -->
<div class="flex flex-wrap content-center gap-2" style="height: 180px">
<div>1</div><div>2</div><div>3</div><div>4</div>
</div>Place Shorthands Container/ItemResponsive
Shorthand properties that set both align and justify in one class.
| Class Pattern | Property | Values |
|---|---|---|
| .place-content-{v} | place-content (align-content + justify-content) | center, start, end, between, around, evenly, stretch, baseline |
| .place-items-{v} | place-items (align-items + justify-items) | start, end, center, stretch, baseline |
| .place-self-{v} | place-self (align-self + justify-self) | auto, start, end, center, stretch |
<!-- Center all wrapped content on both axes -->
<div class="flex flex-wrap place-content-center gap-3" style="height:200px">
<div>A</div><div>B</div><div>C</div>
</div>
<!-- Individual item override -->
<div class="flex h-32">
<div class="place-self-start">Top-left</div>
<div class="place-self-center">Center</div>
<div class="place-self-end">Bottom-right</div>
</div>Order Item
Controls the visual order of flex items without changing the DOM order.
| Class | CSS output | Use case |
|---|---|---|
| .order-first | order: -9999 | Visually first regardless of DOM position |
| .order-last | order: 9999 | Visually last regardless of DOM position |
| .order-none | order: 0 | Reset to natural order |
| .order-1 – .order-12 | order: 1–12 | Numeric ordering for up to 12 items |
<!-- DOM order: A B C D — Visual order: C A D B -->
<div class="flex gap-3">
<div class="order-2">A (DOM 1st)</div>
<div class="order-4">B (DOM 2nd)</div>
<div class="order-1">C (DOM 3rd)</div>
<div class="order-3">D (DOM 4th)</div>
</div>
<!-- Move sidebar first on mobile -->
<div class="flex flex-col md:flex-row gap-4">
<main class="order-2 md:order-1">Main</main>
<aside class="order-1 md:order-2">Sidebar first on mobile</aside>
</div>DOM: A B C D — Visual: C A D B
↑ Visual rendering reorders items without touching the DOM. Screen readers see A B C D.
Gap ContainerFrom @mastors/core
Gap utilities are provided by @mastors/core's spacing module and work for both flex and grid containers.
| Class | CSS output | Value |
|---|---|---|
| .gap-0 | gap: 0 | No gap |
| .gap-1 | gap: 0.25rem | 4px |
| .gap-2 | gap: 0.5rem | 8px |
| .gap-4 | gap: 1rem | 16px |
| .gap-6 | gap: 1.5rem | 24px |
| .gap-x-{key} | column-gap: … | Horizontal gap only |
| .gap-y-{key} | row-gap: … | Vertical gap only |
<div class="flex flex-wrap gap-4">...</div>
<div class="flex flex-wrap gap-x-6 gap-y-2">...</div>Responsive Variants Engine
Pattern: {breakpoint}:{utility-class}. All breakpoints are mobile-first (min-width).
| Prefix | Min-width | Target |
|---|---|---|
| (none) | 0px | All viewports — base styles |
| sm: | 640px | Large phones and up |
| md: | 768px | Tablets and up |
| lg: | 1024px | Laptops and up |
| xl: | 1280px | Desktops and up |
| 2xl: | 1536px | Wide screens and up |
<!-- Classic two-pane: stacked on mobile, side-by-side on md+ -->
<div class="flex flex-col md:flex-row gap-6">
<aside class="md:w-64 shrink-0">Sidebar</aside>
<main class="flex-1 min-w-0">Content</main>
</div>
<!-- Center on mobile, space-between on lg+ -->
<nav class="flex justify-center lg:justify-between items-center">
<div>Logo</div>
<ul class="hidden lg:flex gap-8">...</ul>
<button>CTA</button>
</nav>
<!-- Wrap on small, single row on xl+ -->
<div class="flex flex-wrap xl:flex-nowrap gap-4">
<div class="basis-full sm:basis-1/2 xl:flex-1">Card</div>
<div class="basis-full sm:basis-1/2 xl:flex-1">Card</div>
<div class="basis-full sm:basis-1/2 xl:flex-1">Card</div>
<div class="basis-full sm:basis-1/2 xl:flex-1">Card</div>
</div>Sass Mixins
flex-container() Mixin
Configure a complete flex container in a single @include. All parameters are optional.
| Parameter | Type | Default | Description |
|---|---|---|---|
| $direction | String | row | Sets flex-direction |
| $wrap | String | nowrap | Sets flex-wrap |
| $justify | String | flex-start | Sets justify-content |
| $align | String | stretch | Sets align-items |
| $gap | CSS value | null | null | Sets gap (omitted if null) |
| $inline | Boolean | false | Use inline-flex instead of flex |
@use "@mastors/flexer/scss/mixins/flex-container" as *;
// Centered hero container
.hero { @include flex-container($justify: center, $align: center); }
// Card grid — wrapping row with gap
.card-grid { @include flex-container($wrap: wrap, $gap: 1.5rem); }
// Vertical nav sidebar
.sidebar-nav { @include flex-container($direction: column, $align: flex-start, $gap: .5rem); }
// Inline badge
.chip-group { @include flex-container($align: center, $gap: .5rem, $inline: true); }
// Toolbar
.toolbar { @include flex-container($justify: space-between, $align: center, $gap: 1rem); }flex-item() Mixin
Configure a flex child item in one include. Sets flex, align-self, and order together.
| Parameter | Type | Default | Description |
|---|---|---|---|
| $grow | Number | 0 | flex-grow value |
| $shrink | Number | 1 | flex-shrink value |
| $basis | CSS value | auto | flex-basis value |
| $align | String | auto | align-self (omitted when auto) |
| $order | Number | null | null | order (omitted when null) |
@use "@mastors/flexer/scss/mixins/flex-item" as *;
.main-content { @include flex-item($grow: 1, $basis: 0%); }
.sidebar { @include flex-item($grow: 0, $shrink: 0, $basis: 280px); }
.card { @include flex-item($grow: 1, $basis: 300px, $align: center); }
.featured { @include flex-item($grow: 2, $order: 1); }flex-center() Mixin
The single most common flex pattern — centering children on both axes — in one line.
| Mixin | Compiles to | Use case |
|---|---|---|
| flex-center($inline?) | display:flex; align-items:center; justify-content:center | Both axes — icon buttons, hero sections, overlays |
| flex-center-x($inline?) | display:flex; justify-content:center | Main axis only — center a row of items |
| flex-center-y($inline?) | display:flex; align-items:center | Cross axis only — vertically center text + icon |
@use "@mastors/flexer/scss/mixins/flex-center" as *;
// Perfect centering — modal overlay
.overlay { @include flex-center; position: fixed; inset: 0; background: rgba(0,0,0,.5); }
// Inline icon badge
.badge { @include flex-center($inline: true); gap: .35rem; padding: .2rem .5rem; }
// Vertical centering only (icon + text)
.btn { @include flex-center-y($inline: true); gap: .5rem; padding: .5rem 1rem; }flex-center — both axes
flex-center-x — horizontal
flex-center-y — vertical
Generator
Emit a selective subset of flex utilities from a single config map.
| Config key | Type | Utilities emitted when true |
|---|---|---|
| direction | boolean | flex-row, flex-col, flex-row-reverse, flex-col-reverse |
| wrap | boolean | flex-wrap, flex-nowrap, flex-wrap-reverse |
| justify | boolean | justify-start, justify-center, justify-between, etc. |
| align | boolean | items-start, items-center, items-end, items-stretch, items-baseline |
| grow | boolean | grow, grow-0 |
| shrink | boolean | shrink, shrink-0 |
| order | boolean | order-first, order-last, order-none |
| responsive | boolean | Adds breakpoint-prefixed variants to all generated utilities |
@use "@mastors/flexer/scss/generators/flex-generator" as gen;
// Emit only direction + justify + align with responsive variants
@include gen.generate-flex-utilities((
direction: true,
justify: true,
align: true,
responsive: true,
));
// Emit everything
@include gen.generate-flex-utilities((
direction: true, wrap: true, justify: true,
align: true, grow: true, shrink: true, order: true,
responsive: true,
));Common Patterns
Responsive Navbar
<header class="flex items-center justify-between gap-4 px-6 py-3">
<div class="flex items-center gap-3 shrink-0">
<img class="w-8 h-8" src="logo.svg" />
<span class="font-bold">Brand</span>
</div>
<nav class="hidden md:flex items-center gap-8">
<a href="#">Home</a><a href="#">Docs</a><a href="#">Blog</a>
</nav>
<button class="shrink-0 hidden md:inline-flex items-center gap-2">Sign in</button>
<button class="md:hidden"><i class="fa-solid fa-bars"></i></button>
</header>Media Object (Avatar + Content)
<div class="flex items-start gap-4">
<img class="flex-none w-12 h-12 rounded-full object-cover" src="avatar.jpg" />
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between gap-2 mb-1">
<h3 class="font-semibold truncate">Username</h3>
<time class="flex-none text-xs text-muted">2h ago</time>
</div>
<p class="text-sm text-muted line-clamp-2">Comment or description here...</p>
</div>
</div>Responsive Card Grid
<!-- Cards: full on mobile, half on sm, third on lg -->
<div class="flex flex-wrap gap-4">
<article class="basis-full sm:basis-[calc(50%-0.5rem)] lg:basis-[calc(33.333%-1rem)] flex flex-col gap-3 p-5 border rounded-xl">
<img class="w-full rounded-lg aspect-video object-cover" />
<div class="flex-1 flex flex-col gap-2">
<h3 class="font-semibold">Card title</h3>
<p class="text-sm text-muted flex-1">Description</p>
</div>
<div class="flex items-center justify-between">
<span class="text-xs text-muted">Jan 2025</span>
<a class="inline-flex items-center gap-1.5 text-sm font-semibold">Read <i class="fa-solid fa-arrow-right"></i></a>
</div>
</article>
</div>@mastors/gridder
Complete CSS Grid utility class system for the Mastors Framework
@mastors/gridder provides a complete suite of utility classes, SCSS mixins, and named-area layout presets to build any grid layout without writing custom CSS. It plugs into @mastors/core for its class-generation engine and responsive breakpoint system.
Installation
Requires @mastors/core ≥1.0.0 and sass ≥1.80.0 as peer dependencies.
npm
npm install @mastors/gridderpnpm
pnpm add @mastors/gridderyarn
yarn add @mastors/gridder// Full utility + responsive layer (SCSS entry point)
@use "@mastors/core";
@use "@mastors/gridder";
// Or target just the mixins (zero CSS output)
@use "@mastors/gridder/scss/mixins/grid-container" as gc;<!-- Pre-built CSS (no build step) -->
<link rel="stylesheet" href="node_modules/@mastors/gridder/dist/mastors-gridder.css" />Quick Start
The fastest way to get a grid going — just add utility classes to your HTML.
<div class="grid grid-cols-3 gap-4">
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>SCSS Mixins
grid-container() Mixin
Configure a complete CSS Grid layout in a single mixin call. All parameters are optional and default to sensible values.
| Parameter | Type | Default | Description |
|---|---|---|---|
| $cols | String | null | null | grid-template-columns value |
| $rows | String | null | null | grid-template-rows value |
| $gap | CSS value | null | null | shorthand gap (row + column) |
| $col-gap | CSS value | null | null | column-gap only |
| $row-gap | CSS value | null | null | row-gap only |
| $flow | String | row | grid-auto-flow |
| $auto-cols | String | null | null | grid-auto-columns |
| $auto-rows | String | null | null | grid-auto-rows |
| $inline | Boolean | false | true → display: inline-grid |
@use "@mastors/gridder/scss/mixins/grid-container" as gc;
// 3-column layout with 1.5rem gap
.my-layout {
@include gc.grid-container(
$cols: repeat(3, minmax(0, 1fr)),
$gap: 1.5rem,
$flow: row
);
}
// Inline grid with fixed columns and row gap only
.card-row {
@include gc.grid-container(
$cols: repeat(4, 200px),
$row-gap: 1rem,
$inline: true
);
}
// Full app shell
.app-shell {
@include gc.grid-container(
$cols: 200px 1fr,
$rows: auto 1fr auto,
$gap: 0,
$auto-rows: minmax(0, 1fr)
);
min-height: 100vh;
}Result — 3-column 1.5rem gap grid
grid-item() Mixin
Place a grid child item using span and optional start position. Applied to children of a grid container.
| Parameter | Type | Default | Description |
|---|---|---|---|
| $col-span | Number | null | null | columns to span |
| $row-span | Number | null | null | rows to span |
| $col-start | Number | null | null | explicit column start line |
| $row-start | Number | null | null | explicit row start line |
@use "@mastors/gridder/scss/mixins/grid-container" as gc;
// Feature card spans 2 columns
.feature-card { @include gc.grid-item($col-span: 2, $row-span: 1); }
// Start at column 3, span 2 columns
.hero-block { @include gc.grid-item($col-span: 2, $col-start: 3); }
// Sidebar starts at row 2, spans 3 rows
.sidebar { @include gc.grid-item($row-span: 3, $row-start: 2); }Hero spans 2 cols, sidebar is single col
gridder() Mixin
Place a grid item using a named grid area or explicit row/column line placement. When only $area is supplied, emits grid-area: <name>. When any line parameter is supplied, emits the full grid-area: row-start / col-start / row-end / col-end.
| Parameter | Type | Default | Description |
|---|---|---|---|
| $area | String | Number | — | Named area OR row-start line (required) |
| $col-start | Number | null | null | column-start line (triggers explicit mode) |
| $row-end | Number | null | null | row-end line |
| $col-end | Number | null | null | column-end line |
| $align | String | null | null | align-self value |
| $justify | String | null | null | justify-self value |
@use "@mastors/gridder/scss/mixins/grid-container" as gc;
// Named area mode — just the area name
.page { @include gc.grid-container($cols: 1fr 3fr, $rows: auto 1fr auto); }
.page__header { @include gc.gridder(header); }
.page__sidebar { @include gc.gridder(sidebar, $align: start); }
.page__main { @include gc.gridder(main); }
.page__footer { @include gc.gridder(footer); }
// Explicit line mode — row-start / col-start / row-end / col-end
.hero {
@include gc.gridder(1, $col-start: 2, $row-end: 3, $col-end: 4);
// → grid-area: 1 / 2 / 3 / 4;
}gridder-areas() Mixin
Emit grid-template-areas from a variadic list of quoted row strings — one string per row, space-separated area names within each string.
@use "@mastors/gridder/scss/mixins/grid-container" as gc;
// Signature: @mixin gridder-areas($rows...)
// Each $row is a quoted string of space-separated area names
.app-layout {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
@include gc.gridder-areas(
"header header",
"sidebar main",
"footer footer"
);
}
// Children assigned by name
.app-header { @include gc.gridder(header); }
.app-sidebar { @include gc.gridder(sidebar); }
.app-main { @include gc.gridder(main); }
.app-footer { @include gc.gridder(footer); }
// Three-column full-page layout
.dashboard {
display: grid;
grid-template-columns: 200px 1fr 240px;
@include gc.gridder-areas(
"header header header",
"nav content aside",
"footer footer footer"
);
}Named area layout result
Utility Classes
Display ContainerResponsive
Switch an element into a grid formatting context.
| Class | CSS output |
|---|---|
| .grid | display: grid |
| .inline-grid | display: inline-grid |
<div class="grid grid-cols-2 gap-4">...</div>
<span class="inline-grid grid-cols-2 gap-2">...</span>
<!-- Responsive: show as grid on md+ -->
<div class="block md:grid md:grid-cols-3">...</div>Template Columns ContainerResponsive
Set grid-template-columns. Fixed counts 1–12 use equal minmax(0, 1fr) tracks.
| Class | CSS output |
|---|---|
| .grid-cols-1 … .grid-cols-12 | repeat(N, minmax(0, 1fr)) |
| .grid-cols-none | none |
| .grid-cols-subgrid | subgrid |
| .grid-cols-auto | auto |
| .grid-cols-min | min-content |
| .grid-cols-max | max-content |
| .grid-cols-fr | minmax(0, 1fr) |
<!-- 4 equal columns -->
<div class="grid grid-cols-4 gap-3">
<div>A</div><div>B</div><div>C</div><div>D</div>
</div>
<!-- Responsive: 1 col → 2 → 3 → 4 -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
...
</div>Template Rows ContainerResponsive
Set grid-template-rows. Fixed counts 1–6 use equal minmax(0, 1fr) tracks.
| Class | CSS output |
|---|---|
| .grid-rows-1 … .grid-rows-6 | repeat(N, minmax(0, 1fr)) |
| .grid-rows-none | none |
| .grid-rows-subgrid | subgrid |
| .grid-rows-auto | auto |
| .grid-rows-min | min-content |
| .grid-rows-max | max-content |
| .grid-rows-fr | minmax(0, 1fr) |
<!-- 3 equal rows, items fill columns automatically -->
<div class="grid grid-cols-2 grid-rows-3 gap-3" style="height:200px">
<div>1</div><div>2</div>
<div>3</div><div>4</div>
<div>5</div><div>6</div>
</div>Template Areas Container
Named area placement classes and SCSS mixins for custom areas. Area names are used with the built-in .area-* classes or via gridder().
| Class | CSS output |
|---|---|
| .area-header | grid-area: header |
| .area-nav | grid-area: nav |
| .area-sidebar | grid-area: sidebar |
| .area-main | grid-area: main |
| .area-aside | grid-area: aside |
| .area-footer | grid-area: footer |
<div class="layout-holy-grail" style="min-height:200px">
<header class="area-header">Header</header>
<nav class="area-nav">Nav</nav>
<main class="area-main">Main Content</main>
<aside class="area-aside">Aside</aside>
<footer class="area-footer">Footer</footer>
</div>
<!-- SCSS for custom areas -->
<!-- @use "@mastors/gridder/scss/utilities/grid-template-areas" as areas;
.page-layout {
display: grid;
grid-template-columns: 200px 1fr 200px;
@include areas.define-areas(
"header header header",
"nav main aside",
"footer footer footer"
);
}
.page-nav { @include areas.area(nav); }
.page-main { @include areas.area(main); }
.page-aside { @include areas.area(aside); }
-->Auto Flow ContainerResponsive
Control how the auto-placement algorithm places items using grid-auto-flow.
| Class | CSS output |
|---|---|
| .grid-flow-row | grid-auto-flow: row |
| .grid-flow-col | grid-auto-flow: column |
| .grid-flow-dense | grid-auto-flow: dense |
| .grid-flow-row-dense | grid-auto-flow: row dense |
| .grid-flow-col-dense | grid-auto-flow: column dense |
<!-- Column flow: items fill down before moving right -->
<div class="grid grid-cols-3 grid-flow-col gap-3">
<div>1</div><div>2</div><div>3</div>
</div>
<!-- Dense packing fills gaps left by spanning items -->
<div class="grid grid-cols-3 grid-flow-dense gap-3">
<div class="col-span-2">Wide</div>
<div>A</div><div>B</div><div>C</div>
</div>Auto Columns & Auto Rows Container
Size implicitly created grid tracks with grid-auto-columns and grid-auto-rows.
Auto Columns — .auto-cols-*
| Class | Value |
|---|---|
| .auto-cols-auto | auto |
| .auto-cols-min | min-content |
| .auto-cols-max | max-content |
| .auto-cols-fr | minmax(0, 1fr) |
Auto Rows — .auto-rows-*
| Class | Value |
|---|---|
| .auto-rows-auto | auto |
| .auto-rows-min | min-content |
| .auto-rows-max | max-content |
| .auto-rows-fr | minmax(0, 1fr) |
<!-- Column flow with fr-sized implicit columns -->
<div class="grid grid-flow-col auto-cols-fr gap-4">
<div>Auto A</div>
<div>Auto B</div>
<div>Auto C</div>
</div>Gap ContainerFrom @mastors/core
Gap utilities are inherited from @mastors/core. Pattern: .gap-{token}, .gap-x-{token} (column-gap), .gap-y-{token} (row-gap). Keys map to the core spacing scale.
<div class="grid grid-cols-3 gap-6">…</div> <!-- uniform gap -->
<div class="grid grid-cols-3 gap-x-8 gap-y-4">…</div> <!-- separate axes -->
<div class="grid grid-cols-4 gap-0">…</div> <!-- no gap -->Col Span / Start / End Item
Control how many columns an item occupies and where it starts or ends.
Col Span
| Class | Value |
|---|---|
| .col-span-1 … -12 | span N / span N |
| .col-span-full | 1 / -1 |
| .col-auto | auto |
Col Start
| Class | Value |
|---|---|
| .col-start-1 … -13 | grid-column-start: N |
| .col-start-auto | auto |
Col End
| Class | Value |
|---|---|
| .col-end-1 … -13 | grid-column-end: N |
| .col-end-auto | auto |
<div class="grid grid-cols-4 gap-3">
<div class="col-span-2">Spans 2 cols</div>
<div>Single</div>
<div>Single</div>
<div class="col-span-full">Full width</div>
<div class="col-start-2 col-span-3">Start at 2, span 3</div>
</div>Row Span / Start / End Item
Control how many rows an item occupies and where it starts or ends.
Row Span
| Class | Value |
|---|---|
| .row-span-1 … -6 | span N / span N |
| .row-span-full | 1 / -1 |
| .row-auto | auto |
Row Start
| Class | Value |
|---|---|
| .row-start-1 … -7 | grid-row-start: N |
| .row-start-auto | auto |
Row End
| Class | Value |
|---|---|
| .row-end-1 … -7 | grid-row-end: N |
| .row-end-auto | auto |
<div class="grid grid-cols-3 grid-rows-3 gap-3" style="height:220px">
<div class="row-span-2">Tall sidebar (2 rows)</div>
<div>Content A</div>
<div>Content B</div>
<div>Content C</div>
<div class="col-span-2">Footer (2 cols)</div>
</div>Column & Row Shorthand Item
Set the grid-column or grid-row shorthand directly on an item.
grid-column shorthand
| Class | CSS output |
|---|---|
| .grid-col-auto | grid-column: auto |
| .grid-col-1 … .grid-col-12 | grid-column: N |
grid-row shorthand
| Class | CSS output |
|---|---|
| .grid-row-auto | grid-row: auto |
| .grid-row-1 … .grid-row-6 | grid-row: N |
<div class="grid grid-cols-3 gap-3">
<div class="grid-col-2">Placed at column 2</div>
<div class="grid-col-auto">Auto placed</div>
</div>Alignment ContainerItemResponsive
Align all grid items (container-level) or individual items (self-level) along both axes. All alignment classes work for both grid and flex containers.
justify-items — inline axis, all items
| Class | Value |
|---|---|
| .justify-items-start | justify-items: start |
| .justify-items-end | justify-items: end |
| .justify-items-center | justify-items: center |
| .justify-items-stretch | justify-items: stretch |
align-items — block axis, all items (shared with flexer)
| Class | Value |
|---|---|
| .items-start | align-items: start |
| .items-end | align-items: end |
| .items-center | align-items: center |
| .items-stretch | align-items: stretch |
| .items-baseline | align-items: baseline |
place-items — shorthand (align + justify), all items
| Class | Value |
|---|---|
| .place-items-start / -end / -center / -stretch | place-items: <value> |
Self alignment — individual item overrides
| Class Pattern | Property | Values |
|---|---|---|
| .justify-self-{v} | justify-self | auto, start, end, center, stretch |
| .self-{v} | align-self | auto, start, end, center, stretch, baseline |
| .place-self-{v} | place-self | auto, start, end, center, stretch |
<!-- All items centered vertically -->
<div class="grid grid-cols-3 items-center gap-4" style="height:120px">
<div>Short</div>
<div>Medium content that is taller</div>
<div class="self-end">Self end</div>
</div>
<!-- Centered icon inside a grid cell -->
<div class="grid grid-cols-3 place-items-center">
<div class="place-self-start">Top-left</div>
<div class="place-self-center">Center</div>
<div class="place-self-end">Bottom-right</div>
</div>Layout Presets
Gridder ships three production-ready named-area layout presets you can drop into any project immediately.
1 Holy Grail Layout — .layout-holy-grail
Header spanning full width, three-column middle (nav + main + aside), full-width footer.
/* Generated CSS */
.layout-holy-grail {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
grid-template-columns: auto 1fr auto;
grid-template-rows: auto 1fr auto;
}<div class="layout-holy-grail" style="min-height:200px">
<header class="area-header">Header</header>
<nav class="area-nav">Nav</nav>
<main class="area-main">Main Content</main>
<aside class="area-aside">Aside</aside>
<footer class="area-footer">Footer</footer>
</div>
2 Sidebar Layout — .layout-sidebar
Auto-sized sidebar on the left, fluid main content on the right.
.layout-sidebar {
display: grid;
grid-template-areas: "sidebar main";
grid-template-columns: auto 1fr;
}
3 Dashboard Layout — .layout-dashboard
Full-width header, sidebar + content area, full-width footer. Ideal for admin dashboards.
.layout-dashboard {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr auto;
}Responsive Variants Engine
All utilities marked Responsive generate breakpoint-prefixed variants via the @mastors/core responsive engine. Pattern: .{bp}:{class}.
| Prefix | Min-width | Device target |
|---|---|---|
| sm: | 640px | Large phones / small tablets |
| md: | 768px | Tablets |
| lg: | 1024px | Laptops |
| xl: | 1280px | Desktops |
| 2xl: | 1536px | Large screens |
grid / inline-grid
grid-cols-*
grid-rows-*
grid-flow-*
justify-items-*
items-*
place-items-*
justify-self-*
self-*
place-self-*
<!-- 1 col → 2 → 3 → 4 responsive grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
<div>Card A</div>
<div>Card B</div>
<div>Card C</div>
<div>Card D</div>
</div>
<!-- Flow switches to column layout on large screens -->
<div class="grid grid-flow-row lg:grid-flow-col gap-3">
<div>Item 1</div><div>Item 2</div><div>Item 3</div>
</div>
<!-- Centered on small, start-aligned on lg -->
<div class="grid grid-cols-3 place-items-center lg:place-items-start gap-4">
<div>Item</div><div>Item</div><div>Item</div>
</div>Full Class Reference
Every utility class generated by @mastors/gridder in one consolidated table.
| Category | Class | Property | Value |
|---|---|---|---|
| Display | .grid | display | grid |
| .inline-grid | display | inline-grid | |
| Cols | .grid-cols-{1-12} | grid-template-columns | repeat(N, minmax(0, 1fr)) |
| .grid-cols-none | grid-template-columns | none | |
| .grid-cols-subgrid | grid-template-columns | subgrid | |
| Rows | .grid-rows-{1-6} | grid-template-rows | repeat(N, minmax(0, 1fr)) |
| .grid-rows-none | grid-template-rows | none | |
| Flow | .grid-flow-row | grid-auto-flow | row |
| .grid-flow-col | grid-auto-flow | column | |
| .grid-flow-dense | grid-auto-flow | dense | |
| .grid-flow-row-dense | grid-auto-flow | row dense | |
| .grid-flow-col-dense | grid-auto-flow | column dense | |
| Col Span | .col-span-{1-12} | grid-column | span N / span N |
| .col-span-full | grid-column | 1 / -1 | |
| .col-auto | grid-column | auto | |
| Col Start | .col-start-{1-13} | grid-column-start | N |
| .col-start-auto | grid-column-start | auto | |
| Col End | .col-end-{1-13} | grid-column-end | N |
| .col-end-auto | grid-column-end | auto | |
| Row Span | .row-span-{1-6} | grid-row | span N / span N |
| .row-span-full | grid-row | 1 / -1 | |
| .row-auto | grid-row | auto | |
| Row Start | .row-start-{1-7} | grid-row-start | N |
| .row-start-auto | grid-row-start | auto | |
| Row End | .row-end-{1-7} | grid-row-end | N |
| .row-end-auto | grid-row-end | auto | |
| Area | .area-header | grid-area | header |
| .area-nav | grid-area | nav | |
| .area-sidebar | grid-area | sidebar | |
| .area-main | grid-area | main | |
| .area-aside | grid-area | aside | |
| .area-footer | grid-area | footer |
Source files
Entry: scss/index.scss → imports mixins, utilities, and responsive engine.
Root alias: _index.scss → forwards scss/index.scss so @use "@mastors/gridder" works without a bundler alias.