base — foundation tokens, mixins & JS utilities
The fundament for every other CzG UI component. Provides design tokens ($cgui-* variables), responsive/utility SCSS mixins, JS helpers, and keyframe animations. Every other component depends on base — install it first.
The naming convention is strict: every variable, mixin, and JS export is prefixed cgui- / $cgui- / cgui so dropping base into an existing project does not collide with your own $color__*, $small, $radius or other legacy names. Override values are exposed via !default flags.
Files
| File | Contents |
|---|---|
_variables.scss | colors, spacing, typography, layout, radii, shadows, transitions, breakpoints, z-index |
_mixins.scss | 15 reusable mixins (media, hover, focus, truncate, ...) |
_animations.scss | opt-in @keyframes (fade, slide, spin, ...) |
_functions.scss | small SCSS helpers used internally |
utils.js | $, $$, on, debounce, clamp |
outside-click.js | onOutsideClick, offOutsideClick |
Install
npx czg-ui add base
In resources/sass/app.scss — order matters, variables first:
@import 'components/base/variables';
@import 'components/base/mixins';
@import 'components/base/animations'; // optional, only if you use keyframes
// AFTER base imports → other components
@import 'components/button';
@import 'components/slider';
JS — only the helpers you need:
import { $, $$, debounce } from './components/base/utils.js';
import { onOutsideClick } from './components/base/outside-click.js';
Customization — override tokens
Every $cgui-* is declared with !default, so override before @import 'components/base/variables':
// resources/sass/app.scss
$cgui-color-primary: #FF6B00; // brand orange instead of default blue
$cgui-color-brand: #FF6B00;
$cgui-radius: 2px; // sharp corners
$cgui-content: 1200px; // narrower max-width
@import 'components/base/variables';
@import 'components/base/mixins';
Most-overridden tokens
| Token | Default (light) | Default (dark) | What it controls |
|---|---|---|---|
$cgui-color-primary | #003CFF | #5577FF | Brand color (buttons, links) |
$cgui-color-brand | #003CFF | #5577FF | Same role as primary; usually identical |
$cgui-color-secondary | #000000 | #94A3B8 | Secondary actions |
$cgui-radius | 6px | — | Default border-radius for buttons / inputs / cards |
$cgui-font-family-base | system stack | — | Body font |
$cgui-content | 1400px | — | Max content width (.container) |
$cgui-space-base | 8px | — | Base unit for the $cgui-space-N scale |
Dark mode
base ships with a complete dark theme — flip a single flag before @import:
$cgui-dark-mode: true;
@import 'components/base/variables';
@import 'components/base/mixins';
Every color token then resolves to the dark-friendly value. The registry preview uses this to render every component in both themes, so you can visually compare before integrating.
For an opt-in via prefers-color-scheme, do not use $cgui-dark-mode — the flag is compile-time only. Instead, swap CSS custom properties at runtime, or compile two stylesheets.
Token reference
Colors
// Brand
$cgui-color-primary $cgui-color-brand $cgui-color-secondary
$cgui-color-commerce $cgui-color-discount $cgui-color-yellow
$cgui-color-red $cgui-color-green $cgui-color-blue
$cgui-color-access
// Text
$cgui-color-text $cgui-color-text-muted $cgui-color-text-gray
$cgui-color-text-dark $cgui-color-text-light
// Backgrounds
$cgui-color-bg $cgui-color-bg-light $cgui-color-bg-gray
$cgui-color-bg-gray-light $cgui-color-bg-gray-dark $cgui-color-bg-form
$cgui-color-bg-selected $cgui-color-bg-hover $cgui-color-bg-dark
// Borders + status
$cgui-color-border $cgui-color-border-light
$cgui-color-error $cgui-color-success $cgui-color-warning
Spacing scale (multiples of $cgui-space-base = 8px)
$cgui-space-0 // 0
$cgui-space-1 // 4
$cgui-space-2 // 8
$cgui-space-3 // 12
$cgui-space-4 // 16
$cgui-space-5 // 24
$cgui-space-6 // 32
$cgui-space-7 // 48
$cgui-space-8 // 64
$cgui-space-9 // 96
Typography
$cgui-font-family-base, -heading, -mono
$cgui-font-size-xs / sm / md / lg / xl / xxl // 12, 14, 16, 18, 24, 32
$cgui-font-weight-regular / medium / bold // 400, 500, 700
$cgui-line-height-tight / small / normal / loose // 1.2 / 1.35 / 1.5 / 1.75
Layout & radii
$cgui-content // 1400 (max-width pro container)
$cgui-content-medium // 970
$cgui-content-small // 768
$cgui-content-padding // 16
$cgui-radius-sm // 3
$cgui-radius // 6
$cgui-radius-lg // 12
$cgui-radius-pill // 999
$cgui-border-width // 1
Shadows + transitions
$cgui-shadow-sm / -main / -lg
$cgui-ease // all 0.15s ease
$cgui-ease-in // all 0.2s ease-in
$cgui-ease-out // all 0.2s ease-out
$cgui-ease-in-out // all 0.25s ease-in-out
Breakpoints
$cgui-bp-min // 320
$cgui-bp-tiny // 480
$cgui-bp-small // 640
$cgui-bp-medium // 960
$cgui-bp-large // 1280
$cgui-bp-xlarge // 1700
$cgui-bp-max // 1920
Z-index layers
$cgui-z-base // 1
$cgui-z-dropdown // 100
$cgui-z-sticky // 500
$cgui-z-overlay // 900
$cgui-z-modal // 1000
$cgui-z-toast // 2000
$cgui-z-tooltip // 3000
Mixin reference
cgui-media($breakpoint, $direction: up)
Responsive media query. $breakpoint accepts a name (tiny, small, medium, large, xlarge, max) or any custom px value. $direction: up (default, min-width), down (max-width), only (within a 320px window).
.btn {
padding: 8px 16px;
@include cgui-media(medium) { // ≥ 960px
padding: 12px 24px;
}
@include cgui-media(900px, down) { // ≤ 899px (custom)
width: 100%;
}
}
cgui-hover()
Wraps :hover and :focus-visible in @media (hover: hover) so it does not fire on touch devices (avoids the iOS "stuck hover" bug after tap).
.btn {
background: $cgui-color-primary;
@include cgui-hover() {
background: $cgui-color-brand;
}
}
cgui-focus-visible($color: $cgui-color-primary, $offset: 2px)
Removes the default outline on :focus but restores a visible 2px outline on :focus-visible (keyboard-only).
a { @include cgui-focus-visible(); }
.btn { @include cgui-focus-visible(#f00, 4px); }
cgui-visually-hidden()
Hides an element visually while keeping it for screen readers (sr-only).
.skip-link { @include cgui-visually-hidden(); }
cgui-truncate($lines: 1)
Single-line ellipsis or multi-line -webkit-line-clamp.
.product__title { @include cgui-truncate(); } // 1 line
.product__description { @include cgui-truncate(3); } // 3 lines
cgui-pseudo($display: block, $position: absolute, $cgui-content: '')
Boilerplate for ::before / ::after.
.tag::before {
@include cgui-pseudo();
inset: 0;
background: rgba(0,0,0,0.5);
}
cgui-container($max-width: $cgui-content, $padding: $cgui-content-padding)
Centered max-width container with horizontal padding.
.section__inner { @include cgui-container(); }
.narrow { @include cgui-container(800px); }
Other mixins
| Mixin | Use | ||
|---|---|---|---|
cgui-reset-list() | Strip <ul> margin/padding/bullets | ||
cgui-reset-button() | Strip native <button> styles | ||
cgui-aspect-ratio($w, $h) | Wrapper around aspect-ratio property | ||
cgui-scrollbar-thin($thumb, $track) | Slim styled scrollbar (Firefox + WebKit) | ||
cgui-stretched-link() | Whole-card clickable area via absolute pseudo | ||
| `cgui-center-absolute($axis: both \ | x \ | y)` | Center an absolute element |
cgui-surface($padding, $radius, $shadow) | Card surface (bg + border + shadow + padding) |
JS — utils.js
Five micro-utilities, no dependencies. Tree-shakable.
import { $, $$, on, debounce, clamp } from './components/base/utils.js';
// $(selector, root?) — querySelector with optional root
const dropdown = $('.dropdown');
// $$(selector, root?) — querySelectorAll → Array
const tabs = $$('.tab');
// on(el, event, handler, opts?) — addEventListener; returns unsubscribe
const off = on(window, 'scroll', () => console.log('scrolled'));
off(); // remove later
// debounce(fn, wait = 100) — coalesce burst calls
window.addEventListener('resize', debounce(onResize, 200));
// clamp(n, min, max) — restrict number to range
clamp(150, 0, 100); // → 100
JS — outside-click.js
Closes popovers / dropdowns / modals when the user clicks outside the component. Used by dropdown, modal, popover.
import { onOutsideClick, offOutsideClick } from './components/base/outside-click.js';
const dropdown = document.querySelector('.dropdown');
const off = onOutsideClick(dropdown, () => {
dropdown.classList.remove('is-open');
});
// Manually unsubscribe:
off();
// or by element reference:
offOutsideClick(dropdown);
The listener is registered on the next animation frame to avoid catching the same click that opened the component.
Animations (opt-in)
_animations.scss defines @keyframes only — no rules of its own. Import adds a few hundred bytes; skip it if you do not use any.
@import 'components/base/animations';
.toast { animation: cgui-fade-in 0.2s ease; }
.spinner { animation: cgui-spin 1s linear infinite; }
When NOT to use
- Tiny project, no other CzG components — copy the 1-2 utilities you
need manually instead of pulling the whole foundation
- You already have an established design system (Tailwind config,
custom token set) — adopting base would force a parallel system and cost more than it saves
Compatibility note
Earlier base versions shipped legacy aliases ($color__primary, $small, $radius...) for drop-in to old projects. The current version no longer ships them — every component uses $cgui-* exclusively. If you migrate from an old base, search-replace $color__ → $cgui-color-, $small → $cgui-bp-small, etc.
Live preview
ui.czechgroup.cz/component/base — full source files, override examples, dark mode toggle.