CSS is Awesome

Mixins

Mixins are the primary API of css-is-awesome. Every visual decision is token-driven — mixin bodies read from CSS custom properties that the active theme defines, so the same @include produces a sketchbook button, a brutalist button or a corporate button depending on the loaded theme. Consume mixins from your own SCSS and the system stays small, fast and easy to re-skin.

Import setup

Two @use lines cover the whole surface. _mixins.scssis the barrel for core layout, typography, colour, interactive and effect mixins — the atomic vocabulary. Each component partial in scss/components/* exports its own composite mixins (btn-primary, card-base, input-base, etc.) so you only import the components you need and your compiled CSS stays lean.

// your-app.scss
@use 'cia/scss/mixins' as m;
@use 'cia/scss/components/buttons' as b;
@use 'cia/scss/components/forms' as f;

.my-cta {
  @include b.btn-primary();
  @include m.elevation(2);
}

The rest of this page is a reference of every public mixin, grouped by category. Internal helpers (anything prefixed with _ or used only by _generator.scss) are omitted.

Bare-tag styling (opt-in)

By default the library does not touch bare HTML — drop the CSS and you get tokens, utilities and React components, but raw <button>, <table> and <h1> stay browser-default. That keeps the library non-invasive: dropping it into an existing project never silently restyles your nav links or third-party components.

If you want a Pico-style "drop-in and it looks decent" experience, add the bare-tags recipe in one line at the top of your app's SCSS entry:

// your-app.scss
@use 'css-is-awesome/scss/recipes/bare-tags';

// done — h1-h6, p, code, pre, hr, ul, ol, table,
// button, input, select, textarea, label, details
// all styled with the active theme.

The recipe uses normal selectors (specificity 0,0,1) — no @layer or :where() machinery. Override anything with any class-based selector and it wins automatically:

.checkout button {
  background: gold; // (0,1,1) > (0,0,1) — wins
}

Heads up: bare-tag styling is global. If you mount third-party React components that render their own <button> internally (Radix, react-select, react-datepicker, cmdk), they will inherit these rules. Either skip the recipe and write your own scoped wrappers, or copy the recipe contents into a .cia-prose wrapper in your own SCSS to scope it.

Prefer to roll your own? The recipe is just one-line includes per tag — copy the file or write your own:

@use 'css-is-awesome/scss/mixins' as m;
@use 'css-is-awesome/scss/components/buttons' as b;
@use 'css-is-awesome/scss/components/data' as d;

button { @include b.btn(primary); }
table  { @include d.table-base; }
h1     { @include m.type(heading-1); }

Layout

Layout mixins cover flex helpers, responsive grids, page-level scaffolding, containers and dividers. All spacing arguments accept a numeric space token (19) or a t-shirt alias (xs/sm/md/lg/xl).

flex-center

Centers children horizontally and vertically with flexbox.

centered
// signature
@mixin flex-center;

// usage
.hero {
  @include m.flex-center;
}

flex-between

Flex row with space-between — ideal for toolbars and card headers.

@mixin flex-between;

.toolbar {
  @include m.flex-between;
}

stack

Vertical flex stack with a token-aware gap. Default gap is 4.

one
two
three
@mixin stack($gap: 4, $align: stretch);

.feed {
  @include m.stack(3);
}

inline

Horizontal flex row with gap, alignment and wrapping controls.

@mixin inline($gap: 2, $align: center, $wrap: nowrap);

.toolbar {
  @include m.inline(2, center, wrap);
}

container

Page-width container with responsive horizontal padding. Sizes: sm, md, lg, xl, 2xl, full.

@mixin container($size: xl, $px: null);

.page {
  @include m.container(lg);
}

grid

Responsive CSS grid. Pass a column count, auto for auto-fit, or a minimum track size. Collapses to one column below the supplied breakpoint.

1
2
3
@mixin grid($cols: 1, $gap: 4, $bp: md, $min: null);

.gallery {
  @include m.grid(3, $gap: 5);
}

.cards {
  @include m.grid(auto, $min: 250px);
}

subgrid

Child inherits the parent grid's column or row tracks. Direction: columns, rows, both.

@mixin subgrid($direction: columns);

.card {
  @include m.subgrid;
  grid-column: span 3;
}

page-layout

Full-page grid with sticky footer. Variants: default, sidebar-left, sidebar-right. Pair with page-header, page-main, page-footer, page-sidebar grid-area helpers.

@mixin page-layout($variant: default);

body {
  @include m.page-layout(sidebar-left);
}
header { @include m.page-header; }
aside  { @include m.page-sidebar; }
main   { @include m.page-main; }
footer { @include m.page-footer; }

section

Vertical page section with consistent top/bottom padding.

@mixin section($py: 8, $px: null);

section {
  @include m.section($py: 9);
}

row and col

Simple flex row / column with token-aware gap and alignment defaults.

@mixin row($gap: 4, $align: center, $justify: flex-start, $wrap: wrap);
@mixin col($gap: 4, $align: stretch, $justify: flex-start);

.form-row { @include m.row(3); }
.form-col { @include m.col(2); }

inset, inset-x, inset-y, squish

Padding helpers. inset applies even padding on all sides, inset-x/inset-y split axes, squish takes a Y/X pair.

@mixin inset($size: 4);
@mixin inset-x($size: 4);
@mixin inset-y($size: 4);
@mixin squish($y: 2, $x: 4);

divider / divider-vertical

Horizontal or vertical divider with token-aware spacing.

above


below

@mixin divider($color: border-default, $spacing: 4);
@mixin divider-vertical($color: border-default, $spacing: 4);

Breakpoints & container queries

Responsive at viewport and component level. Breakpoint mixins take a token (sm, md, lg, xl,2xl) or a literal width. Container-query mixins pair with container to make components respond to their own width.

bp, bp-down, bp-between

Viewport media queries — min-width, max-width, and ranged.

@mixin bp($size);
@mixin bp-down($size);
@mixin bp-between($min, $max);

.hero {
  font-size: 2rem;
  @include m.bp(md) { font-size: 3rem; }
}

Alias mixins

Convenience aliases for common breakpoint ranges: mobile-only, tablet, tablet-only, desktop, wide.

.nav {
  @include m.mobile-only { display: none; }
  @include m.desktop { display: flex; }
}

container, cq, cq-down, cq-between

Container queries. Name the container with container, then query it with cq variants.

@mixin container($name: null, $type: inline-size);
@mixin cq($size, $name: null);
@mixin cq-down($size, $name: null);
@mixin cq-between($min, $max, $name: null);

.card {
  @include m.container(card);
  @include m.cq(md, card) { display: grid; }
}

Typography

All typography is token-driven. font composes weight, style, size, line-height and letter-spacing in one mixin; type pulls from the named scale (display,heading-1heading-4, body,body-sm, caption, overline).

font

Sets weight, style, size, line-height, letter-spacing from one call. Size/lh/ls accept a token name or a literal value. Pass $family to set a font-family — if it's a name registered via font-load, the registered fallback is auto-applied; if it's a CSS-native value (with comma or var()), it passes through; if it's a single-word name that isn't loaded, the build fails with @error so typos surface at compile time.

@mixin font($type: reg, $size: null, $lh: null, $ls: null, $family: null);

.lede {
  @include m.font(medium, $size: 4, $lh: 2);
}

font-load & font-load-local

Drop a one-off font into a single page or section without forking the theme. font-load registers a Google Fonts URL once (idempotent across the compile), emits the @import, and optionally aliases the loaded family to one of the theme's font tokens (display, script, serif, sans, mono, primary) so the rest of the page can keep using var(--font-display) with no further changes. font-load-local is the sister mixin for self-hosted woff2/ttf via @font-face.

// Load + apply (Google Fonts)
@include m.font-load('Pacifico', 'https://fonts.googleapis.com/css2?family=Pacifico&display=swap');
.headline { @include m.font(reg, 7, $family: 'Pacifico'); }

// Load + alias to a theme token (page-scoped --font-display override)
@include m.font-load('Pacifico', '<url>', $alias: display);

// Self-hosted file
@include m.font-load-local('Untitled Sans', '/fonts/UntitledSans.woff2');

Tip: drop the font-load call inside a per-route CSS Module (e.g. src/app/special-landing/page.module.scss) and Next will scope the font download to that route only — pages that don't import the module never see the font in their network tab.

type

Applies a named type-scale preset: size + weight + line-height + letter-spacing in one include.

heading-1bodyoverline
@mixin type($preset);

h1 { @include m.type(heading-1); }
.label { @include m.type(overline); }

truncate

Single-line ellipsis by default, or multi-line clamp with $lines.

@mixin truncate($lines: 1);

.headline {
  @include m.truncate(2);
}

Colour, borders & effects

These wrap raw theme values in runtime-override-capable custom properties, so a consumer can re-skin a single site without rebuilding the library.

border

Applies a border on all sides, one side, or a list of sides, with token-aware colour.

@mixin border($width: 1px, $style: solid, $color: border-default, $sides: all);

.panel {
  @include m.border($sides: (top, bottom));
}

elevation

Applies a theme-driven shadow level (05).

level 1
level 3
@mixin elevation($level: 2);

.card {
  @include m.elevation(3);
}

Interactive states

Focus ring, hover transitions, disabled state, and a composite interactive mixin that wires hover, active and disabled in one call.

focus-ring

Accessible focus-visible ring using border-focus by default.

@mixin focus-ring($color: border-focus, $width: 3px, $offset: 0);

.btn {
  @include m.focus-ring;
}

hover

One-property transition + hover change in a single line.

@mixin hover($prop, $value, $speed: fast);

.link {
  @include m.hover(color, m.color(action-primary-hover));
}

interactive

Composite: transitions background-color, applies hover + active backgrounds, and disables the element when disabled.

@mixin interactive($bg-hover: interactive-hover, $bg-active: interactive-active);

.row {
  @include m.interactive;
}

transition

Variadic — pass any number of CSS properties plus an optional speed (instant/fast/normal/slow/slower) and easing token (smooth/bounce/etc.). Respects prefers-reduced-motion.

@mixin transition($props...);

.btn {
  @include m.transition(background-color, color, fast, smooth);
}

disabled

Standard disabled styling — dimmed, not-allowed cursor, pointer events off.

@mixin disabled($opacity: 0.5);

sr-only

Visually hide an element while keeping it available to screen readers.

@mixin sr-only;

.skip-link {
  @include m.sr-only;
}

Resets

Strip user-agent styling from common elements.

@mixin button-reset;  // appearance, background, border, padding, cursor
@mixin list-reset;    // list-style + margin + padding
@mixin header-reset;  // h1..h6 within scope
@mixin form-reset;    // input/select/textarea full-width

Animation

Keyframes are declared once and referenced by name. All animation mixins respect prefers-reduced-motion.

animate

Trigger a named animation with configurable speed, delay, iteration and timing. Names live in _animations.scss (fade-in, fade-out, slide-up, slide-down, spin, pulse, shimmer, etc.).

@mixin animate(
  $name,
  $speed: normal,
  $delay: 0s,
  $iteration: 1,
  $fill: both,
  $timing: var(--ease, cubic-bezier(0.33, 0.66, 0.33, 1))
);

.modal { @include m.animate(slide-up); }
.spinner { @include m.animate(spin, $iteration: infinite, $timing: linear); }

animate-on

Interaction-triggered animations. Events: hover, focus, active. Effects: lift, glow, press, fade.

@mixin animate-on($event: hover, $effect: lift);

.card { @include m.animate-on(hover, lift); }

Shortcuts

Pre-baked animation helpers that inject the keyframes in the same call.

@mixin spin($duration: 1s);
@mixin pulse($duration: 2s);
@mixin fade-in($duration: normal);
@mixin slide-up($duration: normal, $distance: 1rem);

Icons

SVG and Font Awesome helpers. Prefer svg for inline icon styling, svg-bg for background-image masks, svg-text for inline-text alignment. Font Awesome mixins require fa-load once at the root to inject the shared @font-face rules.

@mixin svg(...);
@mixin svg-bg(...);
@mixin svg-text(...);

@mixin fa-load;
@mixin fa($name);
@mixin fa-icon($name);
@mixin fa-text($name);
@mixin fa-spin($name, $size, $style);

:root { @include m.fa-load; }
.icon-check { @include m.fa-icon(check); }

Component mixins

Composite mixins live in scss/components/*.scss and compose the atomic mixins above into real UI primitives. Every base mixin wraps its override-controlled properties in var(--<key>, <default>), so a theme can tweak padding, radius, shadow or colour without a rebuild.

Buttons

From components/buttons. Import as @use '.../components/buttons' as b;.

@mixin btn-base($py: 1, $px: 4, $r: md, $font-weight: medium, $font-size: null);
@mixin btn($variant, $bg, $bg-hover, $bg-active, $color, $border, $args...);
// $variant: primary | secondary | outline | ghost | info | success | warning | error | disabled
@mixin btn-icon($size: 2.5rem, $r: md);

// Author your own class — variant is a mixin arg, not a --modifier suffix
.hero-cta      { @include b.btn(primary); }
.checkout-cancel { @include b.btn(outline); }

Data display — cards, lists, tables, avatars

From components/data.

Warm paper

Card-base composes padding, radius, shadow and surface colour.

Themable

Swap the theme — every card re-skins without markup changes.

@mixin table-base($striped: false, $hover: false, $bordered: false, $compact: false);
@mixin table-responsive;

@mixin card-base($p: 4, $r: lg, $shadow: 1, $bg: surface-default);
@mixin card-header($pb: 2);
@mixin card-footer($pt: 2);
@mixin card-interactive;

@mixin list-base($gap: 0, $dividers: false);
@mixin list-item($py: 2, $px: 4, $interactive: false);

@mixin avatar($size: 2.5rem, $r: full);
@mixin avatar-placeholder($size, $r, $bg, $color);
@mixin avatar-group($overlap: -0.5rem);

Feedback — alerts, toasts, badges, tags, progress

From components/feedback. Status-coloured variants read status-* tokens.

@mixin alert-base($py: 2, $px: 4, $r: md, $border-width: 1px);
@mixin alert($status: info, $py: 2, $px: 4, $r: md);
@mixin toast-base($py: 2, $px: 4, $r: lg, $shadow: 3);

@mixin badge-base($py, $px, $r: full, $font-size: 1);
@mixin badge($status: info);
@mixin tag($py: 2xs, $px: 2, $r: md, $font-size: 2, $removable: false);

@mixin progress-track($height, $r: full, $bg: surface-muted);
@mixin progress-fill($color: action-primary-default);
@mixin spinner(...);
@mixin skeleton(...);

Forms — inputs, selects, checks, radios, switches, sliders

From components/forms. All form primitives share the same focus treatment and disabled contract.

@mixin input-base($py: 1, $px: 2, $r: md, $border-width: 1px, $bg, $border-color);
@mixin select-base(...);
@mixin textarea-base(...);

@mixin check-base($size: 1.125rem, $r: sm, $color: action-primary-default);
@mixin radio-base($size: 1.125rem, $color: action-primary-default);
@mixin switch-base(...);
@mixin slider-base(...);

@mixin label-base($size: 2, $weight: medium, $color: text-primary);
@mixin form-layout($columns: 1, $gap: 4);
@mixin form-group($gap: 1, $direction: column);
@mixin form-row($gap: 2, $align: center);
@mixin form-help($color: text-muted);
@mixin form-error;

From components/navigation.

@mixin navbar-base(...);
@mixin navbar-brand($gap: 2);
@mixin navbar-nav($gap: 1);
@mixin navbar-link($py: 1, $px: 2, $r: md);

@mixin nav-base($direction: row, $gap: 1);
@mixin breadcrumb($gap: 1, $separator: "/");

@mixin tabs-base($gap: 0, $border: true);
@mixin tab-item($py: 2, $px: 4, $active-color: action-primary-default);

@mixin pagination($gap: 2xs);
@mixin pagination-item($size: 2.25rem, $r: md);

Overlays — modals, tooltips, popovers, dropdowns

From components/overlay.

@mixin modal-backdrop($bg: rgba(0, 0, 0, 0.5));
@mixin modal-base($p: 5, $r: xl, $shadow: 5, $max-width: 500px);
@mixin modal-header($pb: 2);
@mixin modal-footer($pt: 2);

@mixin tooltip-base($py, $px, $r: md, $bg, $color);
@mixin popover-base($p: 4, $r: lg, $shadow: 3, $max-width: 320px);

@mixin dropdown-menu($py: 1, $r: md, $shadow: 2, $min-width: 12rem);
@mixin dropdown-item($py: 1, $px: 4);
@mixin dropdown-divider($spacing: 1);

Writing your own mixins

When you extend the system, follow the same contract: read every visual value from a token helper (color(), space(), radius(), shadow(), font-size()), wrap override-controlled properties in var(--<key>, <default>) so themes can tweak them at runtime, and compose atomic mixins rather than duplicating their bodies.

// good — token-driven, override-capable
@mixin note-base($p: 4, $r: md, $bg: surface-muted) {
  padding: var(--note-padding, #{m.space($p)});
  border-radius: var(--note-radius, #{m.radius($r)});
  background: m.color($bg);
  @include m.border($sides: left, $color: border-focus);
}

The full contributor guide — naming conventions, parameter order, how to add a mixin to the barrel — lives in CONTRIBUTING.md alongside the component authoring guide.

Full index

Every public mixin at a glance. Jump to the section above for usage examples.

Theme