| name | component-patterns |
| description | SCSS and JS structural patterns for OUDS Web components. Use this skill when creating, editing, or reviewing component SCSS files (scss/_*.scss, scss/forms/_*.scss) or JS component files (js/src/*.js). Covers CSS custom property declarations at top of class, state overrides via variable overrides (not property overrides), scss-docs-start/end markers, border-width compensation with calc(), mask-image icon pattern, responsive breakpoint overrides, and the OUDS mod comment convention. |
Component Patterns
Core principle
Every component declares CSS custom properties at the top of its main selector, then consumes them via var(). State changes (hover, disabled, variants) override the variable, never the property. This creates one source of truth and enables runtime theming.
SCSS structure template
#{$ouds-root-selector} {
--#{$prefix}my-comp-border-radius: #{$ouds-border-radius-default};
}
.my-component {
--#{$prefix}my-comp-padding: #{$ouds-my-comp-space-padding-block};
--#{$prefix}my-comp-color: #{$ouds-color-content-default};
--#{$prefix}my-comp-bg: #{$ouds-color-bg-primary};
padding: var(--#{$prefix}my-comp-padding);
color: var(--#{$prefix}my-comp-color);
background-color: var(--#{$prefix}my-comp-bg);
@include border-radius(var(--#{$prefix}my-comp-border-radius));
@include transition($transition-base);
&:hover {
--#{$prefix}my-comp-bg: #{$ouds-color-bg-secondary};
}
&:focus-visible {
@include focus-visible();
}
&:disabled, &[aria-disabled="true"] {
--#{$prefix}my-comp-color: #{$ouds-color-content-disabled};
pointer-events: none;
}
}
.my-component-variant {
--#{$prefix}my-comp-bg: #{$ouds-color-surface-brand};
}
Key patterns
Documentation markers
The Astro docs site extracts CSS variable tables from these markers. Every component needs them:
Border-width compensation
Prevent layout shift when borders change on interaction:
padding: calc(var(--#{$prefix}btn-padding-y) - var(--#{$prefix}btn-border-width))
calc(var(--#{$prefix}btn-padding-x) - var(--#{$prefix}btn-border-width));
Icon pattern (mask-image)
Icons inherit color from currentcolor:
&::before {
content: "";
background-color: currentcolor;
mask-image: escape-svg(var(--#{$prefix}icon));
mask-size: 100%;
mask-repeat: no-repeat;
}
Responsive overrides
Override the variable at breakpoints, don't duplicate rulesets:
.component {
--#{$prefix}comp-width: #{$mobile};
@include media-breakpoint-up(xl) {
--#{$prefix}comp-width: #{$desktop};
}
}
OUDS mod markers
Every deviation from Bootstrap upstream must be marked:
display: flex;
.btn.loading-indeterminate { ... }