Configuring Modules with @use ... with

Ship configurable libraries: !default variables, @use with (), and forwarding configuration downstream.

The module system turns a stylesheet into a configurable package. A module declares its knobs as !default variables; a consumer overrides them exactly once, at load time, with @use ... with (...).

The contract

  • Only variables marked !default can be configured.
  • A module can be configured once per compilation — the first @use ... with wins, so configure at the top of your entry file.
  • @forward 'lib' with (...) lets an index file pre-configure a dependency it re-exports.
// _config.scss
$primary: #CC6699 !default;
$radius:  4px      !default;

// main.scss
@use 'config' with ($primary: #6699CC);
// $radius keeps its default, $primary is overridden

This is the clean replacement for the old 'set a variable before @import' hack. It is explicit, order-independent within the with block, and impossible to configure twice by accident.

Example

Example · css
// ---- library/_config.scss ----------------------------------
$primary:  #CC6699 !default;
$radius:   8px      !default;
$font:     system-ui, sans-serif !default;

// ---- library/_button.scss -----------------------------------
@use 'config';
.btn {
  background: config.$primary;
  border-radius: config.$radius;
  font-family: config.$font;
}

// ---- library/_index.scss (public entry) ---------------------
@forward 'config';   // re-export the knobs
@forward 'button';

// ---- app/main.scss ------------------------------------------
@use 'library' with (
  $primary: #6699CC,
  $radius:  12px
);
// One block configures the whole package;
// $font falls back to its !default.

When to use it

  • A UI kit uses !default on every configurable variable so downstream projects only declare the variables they want to change via @use 'kit' with ().
  • A responsive grid module exposes $columns and $gutter as !default variables, letting each project configure its own grid without forking the library.
  • A developer forwards a configuration module with !default variables through an index file so parent project config flows down to all sub-modules automatically.

More examples

Library with !default config variables

The library's _config.scss declares all tokens as !default so consuming projects can override any of them when loading the module.

Example · css
// lib/_config.scss
$primary:   #2563eb !default;
$radius:    4px     !default;
$font-sans: system-ui !default;

// lib/buttons.scss
@use 'config';

.btn {
  background:    config.$primary;
  border-radius: config.$radius;
  font-family:   config.$font-sans;
}

Consuming with @use ... with ()

Overrides all three config variables at the @use site; lib/buttons.scss automatically receives the project-specific values.

Example · css
// project/main.scss
@use 'lib/config' with (
  $primary:   #e74c3c,
  $radius:    0,
  $font-sans: 'Roboto, sans-serif'
);
@use 'lib/buttons'; // picks up the configured values

Forwarding config to sub-modules

An index file @forward-s the config and component modules so a single @use ... with () on the index configures the entire library.

Example · css
// lib/_index.scss
@forward 'config';
@forward 'buttons';
@forward 'forms';

// project/main.scss
@use 'lib' with (
  $primary: #7c3aed
);
// $primary flows into config, buttons, and forms via @forward

Discussion

  • Be the first to comment on this lesson.