| project |
|
|||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tech_stack |
|
|||||||||||||||||||||||||
| architecture |
|
|||||||||||||||||||||||||
| constraints |
|
|||||||||||||||||||||||||
| quick_facts |
|
|||||||||||||||||||||||||
| documentation |
|
OUDS Web is a multi-brand design system for the web, built as a fork of Bootstrap 5.3.6. It ships accessible, token-driven UI components for Orange group brands (Orange, Sosh, Orange Compact).
| Key info | Value |
|---|---|
| Version | 1.1.0 |
| Upstream | Bootstrap 5.3.6 |
| Main branch | ouds/main |
| License | MIT (code) / CC BY 3.0 (docs) |
| Docs | https://web.unified-design-system.orange.com/ |
| Repo | https://github.com/Orange-OpenSource/Orange-Boosted-Bootstrap |
- Architecture overview
- Monorepo structure
- Design tokens system
- Multi-brand system
- Components catalog
- Code conventions
- Accessibility requirements
- Quick-start examples
- Anti-patterns
- AI agent workflow
- Extended documentation
OUDS Web is a monorepo with npm workspaces. It publishes:
@ouds/web-common— Shared SCSS source files, JavaScript components (compiled todist/js/). This is the root package.@ouds/web-orange— Orange brand tokens + compiled CSS (dist/css/).@ouds/web-sosh— Sosh brand tokens + compiled CSS.@ouds/web-orange-compact— Orange Compact brand tokens + compiled CSS.
Key principle: JavaScript is shared across all brands. Only CSS/tokens differ per brand.
Consumer installs: @ouds/web-common (JS) + @ouds/web-<brand> (CSS)
| Layer | Technology |
|---|---|
| Markup | Semantic HTML5 |
| Styles | SCSS → CSS (via sass 1.78) + PostCSS (autoprefixer, RTL via rtlcss) |
| Scripts | Vanilla JavaScript (ES modules), bundled with Rollup |
| Tokens | SCSS variables + CSS custom properties |
| Docs site | Astro 5.x with MDX content collections |
| Testing | Karma + Jasmine (JS), Pa11y-CI (a11y), VNU (HTML validation), Stylelint, ESLint |
| Storybook | @storybook/html-vite with a11y addon |
💡 Context queries for AI agents:
- To understand the build pipeline: See
.ai/ARCHITECTURE.md- To explore JS bundling:
grep_search("rollup.config", includePattern="build/*.mjs")- To see all test configurations:
file_search("**/*{.spec,.test}.js")
Orange-Boosted-Bootstrap/
├── package.json # Root: @ouds/web-common — shared JS + SCSS source
├── scss/ # 🔵 Common SCSS (components, mixins, utilities, variables)
│ ├── _variables.scss # Bootstrap variables mapped to OUDS tokens
│ ├── _variables-dark.scss # Dark mode variable overrides
│ ├── _config.scss # $prefix: bs-, $color-mode-type, $ouds-root-selector
│ ├── _functions.scss # Sass functions
│ ├── _maps.scss # Sass maps
│ ├── _mixins.scss # Mixin index
│ ├── mixins/ # 28 mixin files (breakpoints, buttons, focus, grid…)
│ ├── forms/ # 11 form component partials
│ ├── helpers/ # 9 helper classes (visually-hidden, focus-ring, stacks…)
│ ├── utilities/ # _api.scss — utility class generator
│ ├── _accordion.scss # Component partials (one file per component)
│ ├── _buttons.scss
│ ├── _modal.scss
│ └── … # ~40 component SCSS partials
├── js/
│ ├── src/ # 🔵 JavaScript source (ES modules)
│ │ ├── base-component.js # Abstract base class for all components
│ │ ├── alert.js # 15 component modules
│ │ ├── dom/ # 4 DOM helpers (event-handler, data, manipulator, selector-engine)
│ │ └── util/ # 9 utility modules (focustrap, backdrop, swipe, sanitizer…)
│ ├── dist/ # Compiled individual plugins
│ └── tests/ # Unit and integration tests
├── dist/ # 🔵 Compiled common JS output
│ └── js/ # ouds-web.js, .esm.js, .bundle.js (+ minified + sourcemaps)
├── packages/
│ ├── orange/ # 🟠 Orange brand package (@ouds/web-orange)
│ │ ├── package.json
│ │ ├── config.yml # Brand-specific site config (name, CDN URLs, Algolia…)
│ │ ├── scss/
│ │ │ ├── ouds-web.scss # Main entry: imports common + Orange tokens
│ │ │ └── tokens/ # _raw.scss, _semantic.scss, _composite.scss, _component.scss
│ │ │ # + _semantic-colors-custom-props.scss
│ │ │ # + _component-colors-custom-props.scss
│ │ │ # ⚠️ All auto-generated except _composite.scss
│ │ └── dist/css/ # Compiled brand CSS (LTR, RTL, minified)
│ ├── sosh/ # 🟣 Sosh brand package (@ouds/web-sosh)
│ │ └── (same structure as orange)
│ └── orange-compact/ # 🟠 Orange Compact brand package
│ └── (same structure as orange)
├── site/ # 📖 Astro documentation site
│ ├── src/
│ │ ├── content/docs/ # MDX doc pages organized by section
│ │ ├── components/ # Astro components (shortcodes, partials, layouts)
│ │ ├── layouts/ # BaseLayout, DocsLayout, ExamplesLayout…
│ │ ├── libs/ # 18 TypeScript utility modules
│ │ └── pages/ # Brand-parameterized routes: /[brand]/docs/…
│ └── data/ # Shared data files
├── stories/ # 📘 Storybook stories (auto-generated from docs)
├── build/ # 🔧 Build scripts (Rollup, PostCSS, SRI, version, VNU…)
├── fonts/ # Custom font files
└── .storybook/ # Storybook configuration
You must not access files outside this repository.
| File | Purpose |
|---|---|
scss/_config.scss |
CSS prefix (bs-), color-mode type, root selector |
scss/_variables.scss |
All Bootstrap variables remapped to OUDS tokens (~2200 lines) |
packages/<brand>/scss/tokens/_index.scss |
Token import order for each brand |
packages/<brand>/scss/ouds-web.scss |
Brand entry point — imports common + tokens |
packages/<brand>/config.yml |
Brand metadata (name, CDN URLs, docs config) |
build/rollup.config.mjs |
JS build configuration |
build/postcss.config.mjs |
CSS post-processing (autoprefixer) |
💡 Context queries for AI agents:
- To see all SCSS component files:
file_search("scss/_*.scss")- To find a specific component:
semantic_search("button component javascript")- To understand package structure:
read_file("packages/orange/package.json")- To see token import order:
read_file("packages/orange/scss/tokens/_index.scss")
Tokens are the single source of truth for all visual properties. They follow a 3-tier hierarchy.
Tokens flow through this pipeline:
Figma (design) → DTCG export → Style Dictionary → SCSS files → PR on GitHub
- Designers define tokens in Figma.
- Tokens are exported in DTCG format (Design Token Community Group standard).
- Style Dictionary transforms them into SCSS files (
_raw.scss,_semantic.scss,_component.scss,_semantic-colors-custom-props.scss,_component-colors-custom-props.scss). - A pull request is opened on GitHub to integrate the updated token files.
| Token file | Auto-generated? | Editable by hand? |
|---|---|---|
tokens/_raw.scss |
✅ Yes | ❌ Never |
tokens/_semantic.scss |
✅ Yes | ❌ Never |
tokens/_component.scss |
✅ Yes | ❌ Never |
tokens/_semantic-colors-custom-props.scss |
✅ Yes | ❌ Never |
tokens/_component-colors-custom-props.scss |
✅ Yes | ❌ Never |
tokens/_composite.scss |
❌ No | ✅ Yes — manually managed |
_composite.scss is the exception: It contains icons (SVG data URIs), composite elevation tokens, font stacks, and Sass maps that cannot be expressed in the DTCG format. This is the only token file that should be edited by hand.
Raw (primitives) → Semantic → Component
$core-ouds-* $ouds-* $ouds-<component>-*
| Layer | Prefix | Location | Purpose |
|---|---|---|---|
| Raw | $core-ouds-*, $core-orange-* |
tokens/_raw.scss |
Primitive values (colors, dimensions, base units). Never use directly in component SCSS. |
| Semantic | $ouds-* |
tokens/_semantic.scss |
Meaningful aliases (e.g., $ouds-border-radius-default). Maps raw tokens to design intent. |
| Composite | $ouds-* |
tokens/_composite.scss |
Combined values (elevation, font stacks, icons, Sass maps). ✅ Manually managed. |
| Component | $ouds-<component>-* |
tokens/_component.scss |
Per-component tokens (e.g., $ouds-button-border-radius-default). References semantic tokens. |
| CSS Custom Props | --bs-* |
tokens/_*-custom-props.scss |
Runtime tokens exposed as CSS custom properties for color-mode switching. |
// Raw: $core-ouds-{category}-{value}
$core-ouds-border-radius-100: 4px;
// Semantic: $ouds-{category}-{variant}
$ouds-border-radius-default: $core-ouds-border-radius-0;
// Component: $ouds-{component}-{category}-{variant}
$ouds-button-border-radius-default: $ouds-border-radius-default;Raw tokens use a base-multiplier pattern for consistency:
$core-ouds-border-base: 4px !default;
$core-ouds-border-radius-100: $core-ouds-border-base * 1; // 4px
$core-ouds-border-radius-200: $core-ouds-border-base * 2; // 8px
$core-ouds-border-radius-300: $core-ouds-border-base * 3; // 12pxColor tokens are exposed as CSS custom properties to support light/dark mode at runtime:
// In tokens/_semantic-colors-custom-props.scss
@include color-mode(light, true) {
--#{$prefix}color-action-enabled: #{$ouds-color-action-enabled-light};
--#{$prefix}color-bg-primary: #{$ouds-color-bg-primary-light};
}
@include color-mode(dark) {
--#{$prefix}color-action-enabled: #{$ouds-color-action-enabled-dark};
--#{$prefix}color-bg-primary: #{$ouds-color-bg-primary-dark};
}All variables use !default to allow consumer overrides.
💡 Context queries for AI agents:
- To see complete token documentation: See
.ai/DESIGN_TOKENS.md- To find all composite tokens:
grep_search("ouds-elevation|ouds-font-family", includePattern="packages/*/scss/tokens/_composite.scss")- To see how colors work in dark mode:
read_file("packages/orange/scss/tokens/_semantic-colors-custom-props.scss", 1, 50)- To understand token naming:
semantic_search("token naming convention hierarchy")
Each brand package follows the same structure but provides different token values.
- Shared core:
$core-ouds-*tokens are identical across brands (OUDS Core v1.9.0). - Brand-specific:
$core-orange-*/$core-sosh-*tokens differ per brand (colors, fonts, etc.). - Semantic mapping: Each brand maps raw tokens to semantic tokens differently.
- Component tokens: Reference semantic tokens — automatically adapted per brand.
Every brand's ouds-web.scss follows the same structure:
// packages/<brand>/scss/ouds-web.scss
@import "@ouds/web-common/scss/config";
@import "@ouds/web-common/scss/functions";
@import "@ouds/web-<brand>/scss/tokens"; // ← Brand tokens injected here
@import "@ouds/web-common/scss/variables";
@import "@ouds/web-common/scss/variables-dark";
@import "@ouds/web-common/scss/maps";
@import "@ouds/web-common/scss/mixins";
@import "@ouds/web-common/scss/utilities";
// Then all common layout & component imports…
@import "@ouds/web-common/scss/root";
@import "@ouds/web-common/scss/reboot";
// …// packages/<brand>/scss/tokens/_index.scss
@import "raw"; // 1. Primitive values
@import "semantic"; // 2. Semantic mappings
@import "semantic-colors-custom-props"; // 3. CSS custom properties (semantic)
@import "composite"; // 4. Composite tokens (elevation, fonts)
@import "component-colors-custom-props"; // 5. CSS custom properties (component)
@import "component"; // 6. Component-level tokensToken updates follow this workflow:
- Designers update tokens in Figma.
- The pipeline exports DTCG → Style Dictionary → SCSS files.
- A PR is opened on GitHub with the updated token files.
- The PR is reviewed and merged into
ouds/main.
| Action | Where |
|---|---|
| Edit composite tokens (elevation, font stacks, icons, maps) | packages/<brand>/scss/tokens/_composite.scss ✅ |
| Edit raw, semantic, or component tokens | ❌ Never — wait for the generated PR |
| Edit color custom properties | ❌ Never — wait for the generated PR |
💡 Context queries for AI agents:
- To compare brand differences:
semantic_search("core-orange core-sosh brand specific colors")- To see a complete brand entry point:
read_file("packages/orange/scss/ouds-web.scss")- To understand brand config:
read_file("packages/orange/config.yml")
| Component | SCSS | JS | Description |
|---|---|---|---|
| Back to top | _back-to-top.scss |
— | Scroll-to-top button |
| Bullet list | _bullet-list.scss |
— | Styled unordered lists |
| Chips | _chips.scss |
— | Compact interactive elements |
| Footer | _footer.scss |
— | Structured page footer |
| Local navigation | _local-navigation.scss |
— | In-page anchor navigation |
| Orange navbar | _orange-navbar.scss |
orange-navbar.js |
Brand-specific navigation bar |
| Quantity selector | forms/_quantity-selector.scss |
quantity-selector.js |
Numeric stepper input |
| Skeleton | _skeleton.scss |
— | Loading placeholder |
| Star rating | forms/_star-rating.scss |
— | Rating input (CSS-only) |
| Stepped process | _stepped-process.scss |
— | Multi-step progress indicator |
| Sticker | _sticker.scss |
— | Promotional badge/label |
| Tags | _tags.scss |
— | Labeling/categorization elements |
| Title bars | _title-bars.scss |
— | Section header bars |
Accordion, Alert, Badge, Breadcrumb, Button, Button group, Card, Carousel, Collapse, Dropdown, Forms (control, select, range, validation, labels, input-group), Grid, Images, Links, List group, Modal, Nav/Tab, Navbar, Offcanvas, Pagination, Popover, Progress, Scrollspy, Spinner, Table, Toast, Tooltip, Typography.
All JS components extend BaseComponent (js/src/base-component.js) and follow a consistent API:
// Pattern for all JS components
import BaseComponent from './base-component.js'
class MyComponent extends BaseComponent {
static get NAME() {
return 'myComponent'
}
// ...
}Available JS components: Alert, Button, Carousel, Collapse, Dropdown, Modal, Offcanvas, OrangeNavbar, Popover, QuantitySelector, Scrollspy, Tab, Toast, Tooltip.
| What you need | Where to look |
|---|---|
| Component SCSS | scss/_<component>.scss or scss/forms/_<component>.scss |
| Component JS | js/src/<component>.js |
| Component tokens | packages/<brand>/scss/tokens/_component.scss (search for ouds-<component>-*) |
| Component docs | site/src/content/docs/components/<component>.mdx |
| Component tests | js/tests/unit/<component>.spec.js |
💡 Context queries for AI agents:
- To see all component details: See
.ai/COMPONENTS.md- To find component patterns:
semantic_search("BaseComponent extends class pattern")- To list all JS components:
file_search("js/src/*.js")- To see component tokens:
grep_search("ouds-button-", includePattern="packages/*/scss/tokens/_component.scss")
- Semantic elements: Use
<nav>,<main>,<article>,<section>,<header>,<footer>,<aside>appropriately. - Follow Code Guide: Attribute order, self-closing tags, etc.
- WAI-ARIA: Always add appropriate
role,aria-label,aria-expanded,aria-controls, etc. - Color mode: Use
data-bs-theme="light"ordata-bs-theme="dark"on elements (notprefers-color-schememedia queries).
- 2-space indentation, no tabs.
- Variable naming:
$component-state-property-size(e.g.,$nav-link-disabled-color). - Use
!defaulton all SCSS variables (except local/temporary variables). - Use OUDS tokens: Never hardcode colors, dimensions, or spacing.
- Use mixins for
border-radiusandtransition: Direct properties are forbidden by Stylelint. - Use
border: 0, notborder: none. - Never use
lighten()ordarken()— use token-defined colors. - No
outline: nonewithout a visible focus alternative. - Stylelint config: Extends
stylelint-config-twbs-bootstrap. - CSS prefix: All custom properties use
--bs-prefix (defined in_config.scss).
// ✅ Good
.my-component {
padding: $ouds-space-padding-block-medium;
color: var(--#{$prefix}color-content-default);
@include border-radius($ouds-border-radius-default);
@include transition(opacity 0.15s linear);
}
// ❌ Bad
.my-component {
padding: 16px;
color: #333;
border-radius: 4px;
transition: opacity 0.15s linear;
}- No semicolons (enforced by ESLint).
- 2-space indentation.
- Strict mode (
'use strict') required. - No
console.login production code. - Prefer template literals over string concatenation.
- No trailing commas.
- ES module source type in
js/directory. - ESLint config: Extends
xo,xo/browser,plugin:unicorn/recommended.
// ✅ Good
const element = document.querySelector(`[data-bs-target="${selector}"]`);
// ❌ Bad
const element = document.querySelector('[data-bs-target="' + selector + '"]');- Charset: UTF-8
- Line endings: LF (Unix)
- Final newline: Always
- Trailing whitespace: Trimmed
💡 Context queries for AI agents:
- To see complete code conventions: See
.ai/CODE_CONVENTIONS.md- To check linter configs:
file_search("**/.{eslintrc,stylelintrc}*")- To see SCSS mixins:
file_search("scss/mixins/_*.scss")- To understand SCSS variable naming:
semantic_search("$component-state-property-size naming convention")
- WCAG 2.1 Level AA minimum compliance.
- Pa11y-CI automated testing on every build (config:
build/.pa11yci.json). - Storybook a11y addon for development-time checks.
| Requirement | Implementation |
|---|---|
| Color contrast | Minimum 4.5:1 for text, 3:1 for large text and UI components. Use OUDS color tokens. |
| Focus visibility | Never remove :focus styles. Use focus-ring mixin or helper. Always provide visible focus indicators. |
| Focus trapping | Modals and dialogs must trap focus (js/src/util/focustrap.js). |
| Keyboard navigation | All interactive elements must be operable with keyboard alone. |
| ARIA attributes | Use role, aria-label, aria-expanded, aria-controls, aria-live as appropriate. |
| Semantic HTML | Use correct heading hierarchy. Use <button> for actions, <a> for navigation. |
| Touch targets | Minimum 44×44px touch target size (use _target-size.scss mixin). |
| Visually hidden text | Use .visually-hidden class for screen-reader-only content. Never use display: none to hide content that should be announced. |
| Motion | Respect prefers-reduced-motion. Transitions are disabled automatically via Bootstrap's mixin. |
| RTL support | Full RTL layout support via rtlcss. Test with dir="rtl". CSS output includes .rtl.css variants. |
# Run Pa11y-CI accessibility tests (requires local docs server)
npm run docs-accessibility
# Run HTML validation
npm run docs-vnu💡 Context queries for AI agents:
- To see complete accessibility guide: See
.ai/ACCESSIBILITY.md- To find Pa11y config:
read_file("build/.pa11yci.json")- To see focus management patterns:
semantic_search("focustrap focus-ring focus-visible")- To check ARIA patterns:
grep_search("aria-", includePattern="js/src/*.js")
<!-- Alert component with proper accessibility -->
<div class="alert alert-info" role="alert">
<span class="alert-icon">
<span class="visually-hidden">Info</span>
</span>
<p>This is an informational alert.</p>
</div>// scss/_my-component.scss
// 1. Use component tokens (defined in packages/<brand>/scss/tokens/_component.scss)
$ouds-my-component-space-padding: $ouds-space-padding-block-medium !default;
$ouds-my-component-border-radius: $ouds-border-radius-default !default;
// 2. Component styles using tokens
.my-component {
padding: $ouds-my-component-space-padding;
@include border-radius($ouds-my-component-border-radius);
color: var(--#{$prefix}color-content-default);
background-color: var(--#{$prefix}color-bg-primary);
// 3. State variations
&:focus-visible {
@include focus-ring();
}
}// ✅ Use semantic tokens
padding: $ouds-space-padding-block-medium;
border-width: $ouds-border-width-default;
// ✅ Use CSS custom properties for colors (enables dark mode)
color: var(--#{$prefix}color-content-default);
background: var(--#{$prefix}color-bg-primary);
// ✅ Use component tokens for component-specific values
margin: $ouds-card-space-padding-block;
// ❌ Never use raw tokens in components
padding: $core-ouds-dimension-200; // WRONG
color: $core-orange-color-orange-550; // WRONG# Install dependencies
npm install
# Build CSS + JS
npm run dist
# Start local dev servers (all brands in parallel)
npm run start
# → Orange: http://localhost:9001/orange/
# → Sosh: http://localhost:9002/sosh/
# → Orange Compact: http://localhost:9003/orange-compact/
# Run all tests
npm run test
# Lint only
npm run lint| Anti-pattern | Why | Do instead | Detection pattern |
|---|---|---|---|
Hardcode color values (#ff7900, rgb(...)) |
Breaks theming and dark mode | Use var(--#{$prefix}color-*) tokens |
Regex: #[0-9a-fA-F]{3,6}|rgb\( |
Hardcode spacing/dimensions (16px, 1rem) |
Breaks design consistency across brands | Use $ouds-space-* or $ouds-dimension-* tokens |
Look for padding|margin:.*\d+(px|rem) |
Use lighten() / darken() Sass functions |
Not supported, breaks token system | Use the appropriate token variant | Regex: lighten\(|darken\( |
Use border: none |
Stylelint violation | Use border: 0 |
Regex: border:\s*none |
Write border-radius: Xpx directly |
Stylelint violation — must use mixin | Use @include border-radius($value) |
File: scss/**/*.scss, Look for border-radius: without @include |
Write transition: ... directly |
Stylelint violation — must use mixin | Use @include transition(...) |
File: scss/**/*.scss, Look for transition: without @include |
Remove :focus styles |
Accessibility violation | Add visible focus alternative with focus-ring() |
Look for :focus { outline: none } |
| Use raw tokens in component SCSS | Couples components to primitive values | Use semantic or component tokens | Regex: \$core-(ouds|orange|sosh)- in scss/_*.scss |
| Edit auto-generated token files | These are generated from Figma via Style Dictionary | Only edit _composite.scss; wait for generated PRs for the rest |
Files: packages/*/scss/tokens/_raw.scss, _semantic.scss, _component.scss, _*-custom-props.scss |
Edit dist/ or js/dist/ files |
Overwritten on build | Edit source in scss/ and js/src/ |
Any changes in dist/ or js/dist/ directories |
Edit compiled CSS (ouds-web.css) |
Overwritten on build | Edit SCSS source files | Files: packages/*/dist/css/*.css |
Commit dist/ files in PRs |
Not wanted in version control | Let CI build them | Check git diff for dist/ paths |
Use display: none for accessible content |
Hidden from screen readers | Use .visually-hidden |
Look for display: none with semantic content |
Use <div> for interactive elements |
Not keyboard accessible | Use <button> or <a> |
Look for <div onclick= or <div role="button" without proper keyboard handlers |
| Skip ARIA attributes on dynamic UI | Breaks screen reader experience | Always add relevant aria-* attributes |
Components with JS interaction missing aria-expanded, aria-controls, etc. |
Use data-bs-theme via media query |
Breaks explicit theme toggle | Use data-bs-theme attribute on elements |
Look for @media (prefers-color-scheme: for theme switching |
// ❌ BAD
.my-button {
background: #ff7900;
color: #000;
}
// ✅ GOOD
.my-button {
background: var(--#{$prefix}color-action-enabled);
color: var(--#{$prefix}color-content-on-action-enabled);
}// ❌ BAD
.my-card {
border-radius: 8px;
transition: all 0.3s ease;
}
// ✅ GOOD
.my-card {
@include border-radius($ouds-border-radius-medium);
@include transition(all 0.3s ease);
}// ❌ BAD
.my-component {
padding: $core-ouds-dimension-200;
color: $core-orange-color-orange-550;
}
// ✅ GOOD
.my-component {
padding: $ouds-space-padding-block-medium;
color: var(--#{$prefix}color-content-primary);
}# ❌ BAD - Never edit these files directly
packages/orange/scss/tokens/_raw.scss
packages/orange/scss/tokens/_semantic.scss
packages/orange/scss/tokens/_component.scss
# ✅ GOOD - Only edit this file if needed
packages/orange/scss/tokens/_composite.scss
# ✅ GOOD - Wait for auto-generated PR from design team
# When tokens need to change, designers update Figma → PR is created- Which brand(s) are affected? Changes in
scss/affect all brands. Changes inpackages/<brand>/affect only that brand. - Is it a common component or brand-specific? Common SCSS is in the root
scss/directory. - Token layer: Are you modifying raw, semantic, or component tokens?
⚠️ Most token files are auto-generated — only_composite.scsscan be edited by hand.
Component SCSS → scss/_<component>.scss
Component JS → js/src/<component>.js
Brand tokens → packages/<brand>/scss/tokens/
Component tokens → packages/<brand>/scss/tokens/_component.scss
Variables → scss/_variables.scss, scss/_variables-dark.scss
Mixins → scss/mixins/_<name>.scss
Documentation → site/src/content/docs/<section>/<component>.mdx
Tests → js/tests/unit/<component>.spec.js
- Always use design tokens — never hardcode values.
- Follow the existing code style (2-space indent, no semicolons in JS, etc.).
- For new SCSS variables, always add
!default. - For new components, add tokens in
_component.scssfor each brand package. ⚠️ Never edit auto-generated token files (_raw.scss,_semantic.scss,_component.scss,_*-custom-props.scss). Only_composite.scssis manually editable.- Comments: Use
// OUDS mod:prefix when modifying Bootstrap's original code.
# Lint SCSS + JS
npm run lint
# Build all CSS + JS
npm run dist
# Run JS tests
npm run js-test
# Run full test suite
npm run test- Design tokens used (no hardcoded values)
- Accessibility: ARIA attributes, keyboard navigation, focus styles, color contrast
- Dark mode: Colors use CSS custom properties
- RTL: No directional assumptions (use logical properties or let rtlcss handle it)
- Multi-brand: Tokens added in ALL brand packages if needed (
orange,sosh,orange-compact) - Lint passes (
npm run lint) - Build succeeds (
npm run dist) - No
dist/files committed - PR targets
ouds/mainbranch
Decision-making logic for common development scenarios has moved to a dedicated file. See
.ai/DECISION_TREES.mdfor all 4 decision trees:
- Tree 1: Where should I put this code?
- Tree 2: Which design token should I use?
- Tree 3: Do I need to update all brands?
- Tree 4: How should I test this change?
All project terms, acronyms, and technical concepts have moved to a dedicated file. See
.ai/GLOSSARY.mdfor all 154 terms across 9 categories: Project & Architecture, Design Tokens, Tech Stack, Testing & Quality, Accessibility Concepts, Bootstrap Concepts, File Naming & Patterns, Development Workflow, Component-Specific Terms, and Special Prefixes & Conventions.
The
.ai/directory contains detailed documentation on specific topics. Start with this file for an overview, then dive into these references for implementation details. Not sure which file to open? Use.ai/QUICK_LOOKUP.md— it maps any topic or task to the right file and section.
| File | Topics covered | Status |
|---|---|---|
.ai/QUICK_LOOKUP.md |
Topic → file routing index; anti-patterns quick-ref; file map | ✅ Available |
.ai/DECISION_TREES.md |
Where to put code; which token to use; multi-brand updates; testing strategy | ✅ Available |
.ai/GLOSSARY.md |
154 project terms, acronyms, prefixes, and patterns | ✅ Available |
.ai/CODE_CONVENTIONS.md |
Full HTML, SCSS, JS style guide; linter configs; naming conventions; comment patterns | ✅ Available |
.ai/ACCESSIBILITY.md |
WCAG 2.1 AA checklist; ARIA patterns per component type; testing strategy; Pa11y config | ✅ Available |
.ai/DESIGN_TOKENS.md |
Full token reference; layer details; naming scheme; how to add new tokens; brand override guide | ✅ Available |
.ai/COMPONENTS.md |
Full component catalog; component creation guide; SCSS/JS patterns; testing patterns | ✅ Available |
.ai/ARCHITECTURE.md |
Build pipeline details; package publishing; CI/CD; Astro docs site structure | ✅ Available |
.ai/TROUBLESHOOTING.md |
Common Stylelint/ESLint/build/CI/Pa11y errors with root causes and fixes | ✅ Available |
This file was generated to provide context for AI agents and LLMs working on the OUDS Web codebase. Keep it up to date when project architecture, conventions, or tooling changes.