@teqaniyah/stable
v1.2.2
Published
Framework-agnostic SCSS design system with CSS custom properties, accessibility, and RTL support
Maintainers
Readme
Stable CSS Framework
A framework-agnostic SCSS design system with CSS custom properties, accessibility, and RTL support.
Quick Start
npm install
npm run build # Compressed CSS + source map
npm run build:expanded # Expanded CSS + source map
npm run watch # Watch modeImport in your SCSS: @use 'scss/style';
CSS Custom Properties
Override any token on :root for runtime theming.
Colors
| Token | Value | Notes |
|-------|-------|-------|
| --primary | #2563eb | blue-600, 4.6:1 contrast |
| --secondary | #4b5563 | gray-600, 7.0:1 |
| --success | #16a34a | green-600 |
| --info | #0284c7 | sky-600 |
| --warning | #d97706 | amber-600 |
| --danger | #dc2626 | red-600 |
| --light | #f3f4f6 | gray-100 |
| --dark | #111827 | gray-900 |
Grayscale: --gray-50 through --gray-900 (50, 100, 200, 300, 400, 500, 600, 700, 800, 900).
Typography
| Token | Value |
|-------|-------|
| --font-sans | system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif |
| --font-mono | ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace |
| --font-size-base | 1rem (16px) |
| --fw-light / --fw-normal / --fw-medium / --fw-semibold / --fw-bold | 300 / 400 / 500 / 600 / 700 |
Spacing (4px base)
--space-{n} where n = 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20
| Token | Value |
|-------|-------|
| --space-0 | 0 |
| --space-1 | 0.25rem (4px) |
| --space-2 | 0.5rem (8px) |
| --space-4 | 1rem (16px) |
| --space-8 | 2rem (32px) |
| --space-16 | 4rem (64px) |
| --space-20 | 5rem (80px) |
Borders, Shadows & Focus
| Token | Value |
|-------|-------|
| --border-color | #e5e7eb |
| --border-radius | 0.375rem (6px) |
| --shadow-sm | 0 1px 2px 0 rgba(0,0,0,0.05) |
| --shadow | 0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1) |
| --shadow-md | 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1) |
| --shadow-lg | 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1) |
| --focus-ring | 0 0 0 2px rgba(37,99,235,0.5) |
| --transition-duration | 200ms |
| --transition-timing | cubic-bezier(0.4, 0, 0.2, 1) |
Breakpoints
| Name | Min-width | Container max-width | |------|-----------|---------------------| | xs | 0 | — | | sm | 640px | 640px | | md | 768px | 768px | | lg | 1024px | 1024px | | xl | 1280px | 1280px | | xxl | 1536px | 1536px |
Responsive classes follow the pattern {class}-{bp}, e.g. .col-md-6, .d-lg-flex, .text-xl-center.
SCSS Mixins
@include bp-up(md) { /* min-width: 768px */ }
@include bp-down(lg) { /* max-width: 1023.98px */ }
@include bp-between(sm, lg) { /* range */ }
@include on-mobile { /* < 640px */ }
@include on-tablet { /* 768px - 1024px */ }
@include on-desktop { /* >= 1280px */ }Grid
12-column flexbox grid with 1.5rem (24px) gutters.
Containers
.container— Responsive max-width.container-fluid— 100% width.container-{bp}— Fixed max-width from breakpoint (sm/md/lg/xl/xxl)
Rows & Columns
<div class="container">
<div class="row">
<div class="col-md-8">Main</div>
<div class="col-md-4">Sidebar</div>
</div>
</div>| Class | Description |
|-------|-------------|
| .row | Flex wrapper with --gutter-x/--gutter-y custom properties |
| .col | Auto equal-width |
| .col-auto | Content-width |
| .col-{1-12} | Fixed span |
| .col-{bp}-{1-12} | Responsive span |
| .row-cols-{1-6} | Equal columns per row |
| .row-cols-{bp}-auto | Auto-width children per breakpoint |
| .offset-{0-11} | Margin offset |
| .order-first / .order-last / .order-{0-12} | Flex ordering |
Gutters
| Class | Effect |
|-------|--------|
| .g-{0-20} | Both axes |
| .gx-{0-20} | Horizontal only |
| .gy-{0-20} | Vertical only |
| .g-{bp}-{0-20} | Responsive gutters (all axes) |
| .gx-{bp}-{0-20} | Responsive horizontal gutters |
| .gy-{bp}-{0-20} | Responsive vertical gutters |
Utilities
All utilities support responsive variants: .{class}-{bp}. Spacing/sizing values use the --space-{n} scale.
Display
.d-none .d-block .d-flex .d-inline-flex .d-grid .d-inline .d-inline-block .d-table .d-contents
Flexbox
| Category | Classes |
|----------|---------|
| Direction | .flex-row .flex-column .flex-row-reverse .flex-column-reverse |
| Wrap | .flex-wrap .flex-nowrap .flex-wrap-reverse |
| Grow/Shrink | .flex-grow-0 .flex-grow-1 .flex-shrink-0 .flex-shrink-1 .flex-fill |
| Justify | .justify-start .justify-end .justify-center .justify-between .justify-around .justify-evenly |
| Align items | .align-items-start .align-items-end .align-items-center .align-items-baseline .align-items-stretch |
| Align self | .align-self-auto .align-self-start .align-self-end .align-self-center .align-self-baseline .align-self-stretch |
| Gap | .gap-{0-20} |
Spacing
| Prefix | Applies to |
|--------|------------|
| .m-{0-20} | Margin (all sides) |
| .mx- .my- | Margin inline / block |
| .mt- .mb- .ms- .me- | Margin top / bottom / start / end |
| .p-{0-20} | Padding (all sides) |
| .px- .py- | Padding inline / block |
| .pt- .pb- .ps- .pe- | Padding top / bottom / start / end |
Auto margins: .m-auto .mx-auto .mt-auto .mb-auto .ms-auto .me-auto
Sizing
| Class | Value |
|-------|-------|
| .w-25 .w-50 .w-75 .w-100 .w-auto .w-full .w-screen | Width |
| .h-25 .h-50 .h-75 .h-100 .h-auto .h-full .h-screen | Height |
| .mw-100 .mw-none | Max-width |
| .mh-100 .mh-none | Max-height |
| .min-w-0 .min-w-full | Min-width |
| .min-h-0 .min-h-full .min-h-screen | Min-height |
Typography
| Category | Classes |
|----------|---------|
| Alignment | .text-start .text-center .text-end |
| Size | .fs-xs .fs-sm .fs-base .fs-lg .fs-xl .fs-2xl .fs-3xl .fs-4xl |
| Weight | .fw-light .fw-normal .fw-medium .fw-semibold .fw-bold |
| Style | .fst-italic .fst-normal |
| Line height | .lh-none .lh-tight .lh-normal .lh-loose |
| Transform | .text-lowercase .text-uppercase .text-capitalize |
| Decoration | .text-decoration-none .text-decoration-underline .text-decoration-line-through |
| Wrap | .text-wrap .text-nowrap .text-truncate .text-break |
Borders
| Category | Classes |
|----------|---------|
| Add/remove | .border .border-0 .border-top .border-end .border-bottom .border-start |
| Style | .border-solid .border-dashed .border-dotted .border-double .border-none |
| Width | .border-{0-6} .border-8 .border-10 .border-12 .border-16 .border-20 |
| Color | .border-{primary\|secondary\|success\|info\|warning\|danger\|light\|dark} .border-gray-{100-500} |
| Radius | .rounded-none .rounded-sm .rounded-md .rounded-lg .rounded-xl .rounded-2xl .rounded-full |
Shadows & Transitions
.shadow-sm.shadow.shadow-md.shadow-lg.shadow-none.transition-none.transition-all.transition-colors.transition-opacity.transition-transform
Position & Layout
.position-static.position-relative.position-absolute.position-fixed.position-sticky.top-{0|50|100}.bottom-{0|50|100}.start-{0|50|100}.end-{0|50|100}.inset-0.translate-middle.translate-middle-x.translate-middle-y.float-start.float-end.float-none.overflow-auto.overflow-hidden.overflow-visible.overflow-scroll(also-xand-yvariants).z-n1.z-0.z-1.z-2.z-3.z-10.z-50.z-auto
Misc
.visible.invisible.opacity-{0|5|10|25|50|75|100}.object-contain.object-cover.object-fill.object-none.object-scale-down.cursor-auto.cursor-default.cursor-pointer.cursor-wait.cursor-not-allowed.cursor-grab.user-select-all.user-select-auto.user-select-none.pe-none.pe-auto
Components
All components use BEM naming (.block__element--modifier).
Accordion
<div class="accordion">
<div class="accordion__item">
<button class="accordion__header" aria-expanded="false">
Title
<span class="accordion__icon"></span>
</button>
<div class="accordion__body" aria-hidden="true">
<div class="accordion__content">Content here</div>
</div>
</div>
</div>Modifiers: .accordion--sm .accordion--lg
State: add is-open class + toggle aria-expanded/aria-hidden.
Breadcrumb
<ul class="breadcrumb">
<li class="breadcrumb__item"><a href="/">Home</a></li>
<li class="breadcrumb__item"><a href="/docs">Docs</a></li>
<li class="breadcrumb__item">Current Page</li>
</ul>Separators (/) are auto-generated. RTL-aware.
Card
<div class="card">
<div class="card__image"><img src="..." alt=""></div>
<div class="card__body">
<h3 class="card__title">Title</h3>
<p class="card__text">Description</p>
<a href="#" class="card__link">Read more</a>
</div>
<div class="card__footer">Footer</div>
</div>Modifiers: .card--outlined .card--{primary|secondary|success|info|warning|danger|light|dark}
Custom props: --card-padding --card-radius --card-bg --card-shadow
Modal
<dialog class="modal">
<div class="modal__header">
<h2 class="modal__title">Title</h2>
<button class="modal__close" aria-label="Close"></button>
</div>
<div class="modal__body">Content</div>
<div class="modal__footer">Actions</div>
</dialog>Modifiers: .modal--sm (24rem) .modal--lg (48rem) .modal--xl (64rem)
Pagination
<ul class="pagination">
<li class="pagination__item"><a href="#">1</a></li>
<li class="pagination__item is-active"><span>2</span></li>
<li class="pagination__item is-disabled"><span>...</span></li>
<li class="pagination__item"><a href="#">3</a></li>
</ul>Table
<div class="table-container">
<table class="table table--striped table--hover">
<thead><tr><th>Name</th><th>Value</th></tr></thead>
<tbody><tr><td>Item</td><td>123</td></tr></tbody>
</table>
</div>Modifiers: .table--striped .table--hover .table--bordered .table--compact .table--responsive
Responsive mode: at mobile, thead becomes sr-only and cells stack vertically.
Tabs
<div class="tabs">
<div class="tabs__nav">
<button class="tabs__tab" aria-selected="true">Tab 1</button>
<button class="tabs__tab">Tab 2</button>
</div>
<div class="tabs__panel">Panel 1</div>
<div class="tabs__panel" hidden>Panel 2</div>
</div>Modifier: .tabs--vertical
Teaser
<article class="teaser">
<div class="teaser__image"><img src="..." alt=""></div>
<div class="teaser__body">
<h3 class="teaser__title">Title</h3>
<p class="teaser__text">Summary text</p>
<a href="#" class="teaser__link">Read more</a>
</div>
</article>Modifiers: .teaser--horizontal .teaser--reversed
Timeline
<div class="timeline">
<div class="timeline__item">
<span class="timeline__date">Jan 2024</span>
<div class="timeline__content">Event description</div>
</div>
</div>Custom props: --timeline-line-color --timeline-dot-size --timeline-dot-color
Items animate in with a staggered fade (up to 20 items).
Tooltip
<span class="tooltip">
Hover me
<span class="tooltip__content">Tooltip text</span>
</span>Placements: .tooltip--top (default) .tooltip--bottom .tooltip--start .tooltip--end
Variant: .tooltip--light
Custom props: --tooltip-bg --tooltip-color --tooltip-padding --tooltip-radius --tooltip-max-width
Layout Helpers
| Class | Description |
|-------|-------------|
| .section | Vertical padding (3rem) |
| .block | Position relative wrapper |
| .collapse | Collapsible container (toggle is-open, set --collapse-height) |
| .header | Sticky header |
| .footer | Dark footer |
Accessibility
- Focus rings —
:focus-visibleoutlines (2px, blue-500) on all interactive elements - Screen reader —
.sr-onlyhides visually,.sr-only-focusablereveals on focus - Reduced motion — All animations/transitions disabled when
prefers-reduced-motion: reduce - RTL — Logical properties throughout; separators and tooltip placements adapt automatically
- ARIA — Components expect
aria-expanded,aria-hidden,aria-selected, andhiddenattributes
Z-Index Scale
| Layer | Value | |-------|-------| | dropdown | 1000 | | sticky | 1020 | | fixed | 1030 | | backdrop | 1040 | | modal | 1050 | | popover | 1060 | | tooltip | 1070 |
