Implement Components, Variants, and Runtime Themes
Create a component layer that consumes semantic tokens instead of depending directly on arbitrary raw values. The button component should have a shared base style and a small number of supported variants. Cards and badges should use the same spacing and border-radius conventions.
Implement light and dark themes using CSS custom properties. Components should reference those properties so that changing the root theme does not require recompiling Sass or duplicating every component selector.
Use a Sass map and @each when generating repeated variant classes. Keep the variant list intentionally small and verify that every generated class corresponds to a supported component state.
If the project uses React, keep the Sass source organized and use CSS Modules where locally scoped styles are appropriate. Global theme properties can be declared in a deliberate global stylesheet.
:root,
[data-theme="light"] {
--surface: #ffffff;
--text: #202020;
--border: #dddddd;
}
[data-theme="dark"] {
--surface: #171717;
--text: #f5f5f5;
--border: #444444;
}
$button-variants: (
primary: #2457c5,
success: #218838,
danger: #c62828
);
.button {
padding: 0.75rem 1rem;
border: 0;
border-radius: 0.5rem;
font: inherit;
cursor: pointer;
&:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
}
@each $name, $color in $button-variants {
.button--#{$name} {
background: $color;
color: white;
}
}
.card {
color: var(--text);
background: var(--surface);
border: 1px solid var(--border);
border-radius: 0.75rem;
}data-theme attribute. The Sass loop generates three button variants, while the card uses semantic custom properties for theme-dependent appearance.
The example uses currentColor for a simple focus outline. Verify its contrast against the surrounding background and adjust the focus-ring design if necessary. Each button variant should also be tested for readable text contrast.Which approach lets the capstone switch between light and dark theme values without recompiling Sass?