Mixins Reference

Mode

Skin

Theme

Overview & Philosophy

Complete reference of @include mixins from scss/config/_mixins.scss. Ashlar separates styling into two layers: a mixin (the recipe) and a component (the default application). Import with @use 'config/mixins' as *; and apply recipes directly to your own semantic selectors.

Two-Layer Architecture: Mixins + Components

Every visual style has two layers: a mixin (recipe) and a component (default application).

Mixin (recipe)

// scss/config/mixins/_table.scss
@mixin table-base {
  @include w-full;
  @include bg-primary;
  @include rounded-lg;
  // ... styles
}

Component (default)

// scss/components/_table.scss
table {
  @include table-base;
}

@media (max-width: 768px) {
  table { @include table-responsive; }
}

When to use which selector

SituationMixinComponent selector
Universal element (label, table, input)yestable { @include table-base; }
Page-level singletonyes.breadcrumbs { @include breadcrumbs; }
Component class (.btn, .collapsible)yes.btn { @include btn; }
Data-attr JS ([data-ln-tabs])not needed[data-ln-tabs] nav { ... }

Project overrides — 4 levels

NeedApproachExample
Use default Do nothing — library CSS works <table>...</table>
Different color Override CSS variable on parent #danger-zone { --color-primary: var(--color-error); }
Different structure Re-apply mixin with modifications #audit-log { @include table-base; @include table-striped; }
Full replace Use only the mixin on custom selector Exclude component, write from scratch

Override Architecture — Zero Hardcoded Colors

Mixins NEVER contain concrete color values (#fff, rgb(), hsl(0 0% 100%)). Every color reads from a CSS custom property token: var(--color-*). This is what makes the entire system work — colors are inherited through the CSS cascade, not baked into mixin definitions.

WRONG

// Hardcoded — breaks inheritance
.ln-modal header {
  background-color: hsl(var(--color-primary));
  border-bottom: none;
  color: #fff;
}

CORRECT

// Mixin reads tokens, project just uses it
.ln-modal header {
  @include panel-header;
}

// Want a different color? Override the token
.ln-modal {
  --color-primary: 280 60% 50%;
  // header automatically inherits
}

When to use which approach

NeedApproachExample
Different color Override CSS variable on parent element .ln-modal { --color-primary: 280 60% 50%; }
Different structure (padding, layout, shape) Override the mixin in project _overrides.scss @mixin panel-header { @include px(2rem); ... }
Both Override mixin for structure + CSS variable for color Mixin override + .parent { --color-primary: ...; }

Example: overriding btn in a project

ln-ashlar default

// scss/config/_mixins.scss (ln-ashlar)
@mixin btn {
  @include flex;
  @include items-center;
  @include px(1rem);
  @include py(0.5rem);
  @include text-sm;
  @include rounded-md;
  @include cursor-pointer;
  @include transition;
  border: none;
  outline: none;
  white-space: nowrap;
}

Project override

// project/scss/_overrides.scss
@mixin btn {
  @include inline-flex;
  @include items-center;
  @include px(1.5rem);
  @include py(0.75rem);
  @include text-base;      // larger text
  @include font-medium;
  white-space: nowrap;
}

// Project selectors — UNCHANGED
#save-user   { @include btn; }
#delete-user { @include btn; }
.form-actions button { @include btn; }

How to set up the override

// project/scss/main.scss
// 1. Import ln-ashlar (loads default mixins)
@use 'ln-ashlar/scss/ln-ashlar';

// 2. Import project overrides AFTER ln-ashlar
//    This file redefines mixins with the same name
@use 'overrides';

// 3. Import project pages (use the mixins — they get the overridden version)
@use 'pages/users';
@use 'pages/dashboard';

Spacing

Accept any CSS value or var(--size-*) token.

MixinOutput
@include p($val)padding: $val
@include px($val)padding-left + padding-right
@include py($val)padding-top + padding-bottom
@include pt($val), pb, pl, prIndividual padding sides
@include m($val)margin: $val
@include mx($val)margin-left + margin-right
@include my($val)margin-top + margin-bottom
@include mt($val), mb, ml, mrIndividual margin sides
@include gap($val)gap: $val
article {
  @include px(var(--size-lg));
  @include py(var(--size-md));
  @include mb(1rem);
}

Display & Flex

MixinOutput
@include flexdisplay: flex
@include inline-flexdisplay: inline-flex
@include blockdisplay: block
@include inline-blockdisplay: inline-block
@include hiddendisplay: none
@include flex-coldisplay: flex; flex-direction: column
@include flex-rowdisplay: flex; flex-direction: row
@include flex-wrapflex-wrap: wrap
@include flex-1flex: 1
@include flex-shrink-0flex-shrink: 0
@include items-centeralign-items: center
@include items-startalign-items: flex-start
@include items-endalign-items: flex-end
@include justify-centerjustify-content: center
@include justify-betweenjustify-content: space-between
@include justify-endjustify-content: flex-end
@include flex-centerdisplay: flex; align-items: center; justify-content: center

Width & Height

MixinOutput
@include w-fullwidth: 100%
@include h-fullheight: 100%
@include min-h-screenmin-height: 100vh
@include size($val)width: $val; height: $val

Typography

MixinOutput
@include text-xsfont-size: var(--text-xs); line-height: 1rem
@include text-smfont-size: var(--text-sm); line-height: 1.25rem
@include text-basefont-size: var(--text-base); line-height: 1.5rem
@include text-lgfont-size: var(--text-lg); line-height: 1.75rem
@include text-xlfont-size: var(--text-xl); line-height: 1.75rem
@include text-2xlfont-size: var(--text-2xl); line-height: 2rem
@include font-normalfont-weight: var(--font-normal)
@include font-mediumfont-weight: var(--font-medium)
@include font-semiboldfont-weight: var(--font-semibold)
@include font-boldfont-weight: var(--font-bold)
@include text-left, text-center, text-rightText alignment
@include uppercase, lowercase, capitalize, normal-caseText transform
@include tracking-wideletter-spacing: 0.025em
@include tracking-widerletter-spacing: 0.05em
@include truncateoverflow: hidden; text-overflow: ellipsis; white-space: nowrap
@include whitespace-nowrapwhite-space: nowrap
@include font-monofont-family: var(--font-mono)
@include font-sansfont-family: var(--font-sans)

Colors

MixinOutput
@include text-primarycolor: var(--color-fg)
@include text-whitecolor: hsl(var(--color-white))
@include text-errorcolor: hsl(var(--color-error))
@include text-successcolor: hsl(var(--color-success))
@include text-warningcolor: hsl(var(--color-warning))
@include bg-primarybackground-color: var(--color-bg)

Borders & Radius

MixinOutput
@include borderborder: 1px solid hsl(var(--color-border))
@include border-t, border-b, border-l, border-rIndividual border sides
@include border-noneborder: none
@include rounded-smborder-radius: var(--radius-sm) — 2px
@include rounded-mdborder-radius: var(--radius-md) — 6px
@include rounded-lgborder-radius: var(--radius-lg) — 8px
@include rounded-xlborder-radius: var(--radius-xl) — 12px
@include rounded-fullborder-radius: 9999px

Shadows

MixinOutput
@include shadow-noneNo shadow
@include shadow-xsVery subtle depth (0 1px 2px)
@include shadow-smSubtle multi-layer shadow
@include shadow-mdMedium shadow
@include shadow-lgLarge shadow
@include shadow-xlExtra large shadow

Transitions

MixinOutput
@include transitiontransition: all var(--transition-base)
@include transition-fasttransition: all var(--transition-fast)
@include transition-slowtransition: all var(--transition-slow) (0.3s)
@include transition-colorsTransitions only color, background-color, border-color

Position & Overflow

MixinOutput
@include relative, absolute, fixed, stickyPosition values
@include sticky-top($top: 0)position: sticky; top: $top; z-index: var(--z-sticky)
@include inset-0top: 0; right: 0; bottom: 0; left: 0
@include overflow-hiddenoverflow: hidden
@include overflow-autooverflow: auto
@include overflow-x-autooverflow-x: auto with touch scrolling

Cursor & Interaction

MixinOutput
@include cursor-pointercursor: pointer
@include cursor-not-allowedcursor: not-allowed
@include select-noneuser-select: none
@include opacity-50opacity: 0.5

Z-Index

MixinOutput
@include z-dropdownz-index: var(--z-dropdown)
@include z-stickyz-index: var(--z-sticky)
@include z-overlayz-index: var(--z-overlay)
@include z-modalz-index: var(--z-modal)
@include z-toastz-index: var(--z-toast)
@include z($val)z-index: $val

Container Queries

Parent declares the container context, child queries it with native @container. Never combine container-type with overflow: hidden on the same element.

MixinOutput
@include containercontainer-type: inline-size
@include container(name)container-type: inline-size; container-name: name
// Parent — declares the context
#sidebar { @include container(sidebar); }

// Child — queries the container
#sidebar nav {
  @container sidebar (min-width: 580px) {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
  }
}

Standard breakpoints

WidthUse
480px1 → 2 columns (narrow containers)
580px1 → 2 columns (standard)
880px2 → 3 columns
1120px3 → 4 columns

Collapsible

Grid-based expand/collapse animation. Uses grid-template-rows: 0fr/1fr transition.

MixinRole
@include collapsibleParent — display: grid with 0fr → 1fr transition. Toggled by .open class
@include collapsible-contentChild — overflow: hidden to clip content
.my-panel          { @include collapsible; }
.my-panel > section { @include collapsible-content; }

Grid Layouts

MixinColumnsResponsive
@include grid1 → 2 → 3768px → 2col, 1024px → 3col
@include grid-21 → 2768px → 2col
@include grid-41 → 2 → 4768px → 2col, 1024px → 4col
@include form-grid6-column grid<768px → 1col. Children use grid-column: span N
@include stack($gap)Flex columnVertical stack with configurable gap (default: 1rem)
// Responsive grid
#products { @include grid; }

// Form layout — 6 columns
#my-form {
  @include form-grid;
  > label { grid-column: span 3; }            // half
  > label:nth-child(3) { grid-column: span 6; } // full
  > .form-actions { grid-column: span 6; }
}

Card & Section

MixinDescription
@include cardWhite bg, light border, shadow-sm, rounded, hover shadow-md
@include card-accent-top3px colored border-top (reads --color-primary)
@include card-accent-bottom3px colored border-bottom
@include card-accent-left3px colored border-left (side status)
@include card-bgSoft tinted background from --color-primary
@include card-stackedPseudo-element "stacked cards" depth illusion
@include panel-headerFlex header bar with border-bottom. Styles nested h3
@include sectionMargin-bottom + header with border-bottom, styles h2 and .section-actions
@include section-cardComplete card with header (panel-header), main (padding), footer (border-top)
// Semantic usage
#user-profile { @include section-card; }

// Card variants — color via --color-primary override
#alerts  { @include card; @include card-accent-top; --color-primary: var(--color-error); }
#status  { @include card; @include card-accent-left; --color-primary: var(--color-success); }
#welcome { @include card; @include card-bg; }
#archive { @include card; @include card-stacked; }

Buttons

Two-tier system: structure is global, color is semantic.

MixinDescription
@include btnComplete action button: structure (inline-flex, padding, font) + filled primary color. For non-submit action buttons via project SCSS.
@include btn-smSize modifier: less padding, text-xs. Apply after @include btn.
@include btn-lgSize modifier: more padding, text-base. Apply after @include btn.
@include btn-groupRow action button group: inline-flex, small gap, no list style. A .btn-group utility class is also shipped for prototyping (same as .btn) — production uses @include on a semantic selector.

Global button tiers

TierHowResult
1. Neutral<button type="button"> — no classTransparent bg, muted text, gray hover. Cancel/Close/Toggle.
2. Primary<button type="submit"> — no classPrimary fill color + white text. Color-only override on top of tier 1 structure.
3. Action@include btn on a semantic selector (or class="btn" for prototyping)Filled primary color. Same as tier 2 but for non-submit action buttons.

Live demo

Color change — override --color-primary

Set --color-primary on the element or any parent. All states (hover, active, focus-ring) adapt automatically.

/* Project semantic selectors — correct approach */
#delete-user  { @include btn; --color-primary: var(--color-error); }
#approve-user { @include btn; --color-primary: var(--color-success); }

/* Context override — all submit + action buttons inside change */
.danger-zone  { --color-primary: var(--color-error); }

/* Custom brand color */
:root { --color-brand: 280 60% 50%; }
.brand-section { --color-primary: var(--color-brand); }

Form

All form mixins live in scss/config/mixins/_form.scss. The component file scss/components/_form.scss applies them to default element selectors.

MixinDescription
@include form-labelBlock label: text-sm, font-medium, text-primary, margin-bottom
@include form-grid6-column grid → 1-column on mobile. Children use grid-column: span N
@include form-actionsFlex row with justify-end, gap, border-top, margin-top
@include form-inputBase input styling: border, focus ring, placeholder, disabled state
@include form-textareaMin-height 6rem, vertical resize
@include form-selectCustom appearance with SVG arrow indicator
@include form-input-icon-groupLabel wrapping icon(s) + input. Handles flex layout and focus ring
@include form-checkBase checkbox/radio: appearance none, custom border, checked state
@include form-checkboxCheckbox: form-check + rounded-sm corners
@include form-radioRadio: form-check + circle + dot indicator
@include form-validate-invalidInvalid input: error border color + error focus ring
@include form-validate-validValid input: success border color + success focus ring
@include form-validate-errorsError message list: no bullets, caption size, error color, top margin
@include pill-outlineBase pill label: structure + visible border + visible input indicator
@include pillFilled pill label: extends pill-outline, gray bg, colored on checked, input hidden
@include pill-groupJoined pills (base modifier): border-radius on first/last child only
@include pillsJoined-group filled pills: apply to <ul> containing <li><label><input>
@include pills-outlineJoined-group outline pills: apply to <ul> containing <li><label><input>
@include toggle-switchBase switch element (applied to <input type="checkbox">)
@include pill-switchSwitch label: layout with text + switch
@include pills-switchVertical list of switches (applied to <ul>)
@include check-list-outlineVertical label list with pill-outline labels (visible input, bordered)
@include check-listVertical label list with filled pill labels (extends check-list-outline)
// Library default — already applied
input, textarea, select { @include form-input; }
input[type="checkbox"]  { @include form-checkbox; }
label                   { @include form-label; }

// Project override — custom form
#audit-form {
  @include form-grid;
  label { grid-column: span 3; }
  .form-actions { grid-column: span 6; }
}

// Pill outline variant — standalone on label
#role-selector label { @include pill-outline; }

Table

All table mixins live in scss/config/mixins/_table.scss. The component file applies table-base and table-responsive to the table element.

MixinDescription
@include table-baseFull table styling: bg, shadow, rounded, thead, th, td, row hover, last-row border
@include table-responsiveMobile stacked layout: td becomes block, uses data-label for column headers
@include table-stripedOdd-row zebra striping
@include table-section-headerSection header row: bold, colored background
@include table-actionInline action button/link in table cells
// Library default — already applied
table { @include table-base; }
@media (max-width: 768px) { table { @include table-responsive; } }

// Project — striped table with section headers
#server-status {
  @include table-base;
  @include table-striped;
  tr[data-section] td { @include table-section-header; }
  td a { @include table-action; }
}

Breadcrumbs & Loader

MixinDescriptionDefault selector
@include breadcrumbsFlex list with » separator, link hover, [aria-current="page"] for active item.breadcrumbs
@include loaderCSS-only spinner animation (box-shadow based)none — project defines selector
// Breadcrumbs — library applies to .breadcrumbs
// HTML: <nav class="breadcrumbs" aria-label="Breadcrumb">
//           <ol>
//               <li><a href="#">Home</a></li>
//               <li><a href="#">Users</a></li>
//               <li aria-current="page">Edit</li>
//           </ol>
//       </nav>

// Loader — project applies to its own selector
#loading { @include loader; }

Avatar

MixinDescriptionDefault selector
@include avatarProfile button/link with square-ish image (rounded-md) + name/role text. Hover bg, focus ring. Works on <button> and <a>..avatar
// Avatar — profile button with image + name/role
<button class="avatar">
    <img src="avatar.jpg" alt="">
    <span>Sojic<small>Administrator</small></span>
</button>

// As dropdown trigger
<div data-ln-dropdown>
    <button class="avatar" data-ln-toggle-for="user-menu">
        <img src="avatar.jpg" alt="">
        <span>Sojic<small>Administrator</small></span>
    </button>
    <ul id="user-menu" data-ln-toggle>
        <li><a href="#">Edit Profile</a></li>
        <li><a href="#">Logout</a></li>
    </ul>
</div>

Navigation

MixinDescription
@include navGeneral navigation reset: clean list, styled links (hover/active), .nav-icon, .nav-label, .nav-section, .nav-divider. Layout and background come from the parent.
// Sidebar — parent handles layout & bg
aside { @include flex-col; @include h-full; @include bg-primary; }
aside nav { @include nav; }

// Header nav — same mixin, different context
#header nav { @include nav; }

// In HTML:
// <nav data-ln-nav="active">
//   <ul>
//     <li><a href="/">
//       <span class="nav-icon ln-icon-home"></span>
//       <span class="nav-label">Dashboard</span>
//     </a></li>
//   </ul>
// </nav>