Capstone: Build a Reusable Sass Design System
Apply the course concepts by designing a token-driven component library with responsive layouts, theme switching, reusable mixins, generated variants, and production-ready CSS.
Project Brief and Requirements
Build a small design system for a developer dashboard. The dashboard should include a responsive application shell, navigation, cards, buttons, badges, forms, and a theme switcher.
The project should demonstrate a complete Sass workflow rather than a collection of unrelated examples.
Functional requirements
- Centralize primitive and semantic design tokens.
- Organize SCSS using modules and partials.
- Implement reusable container and focus-ring mixins.
- Generate a controlled set of button and badge variants from maps.
- Support responsive layouts using mobile-first media queries.
- Use CSS custom properties for runtime light and dark themes.
- Use CSS Modules when integrating components into React.
- Compile production CSS and inspect the generated output.
- Verify keyboard focus, readable contrast, and narrow-screen behavior.
Suggested directory structure
src/scss/
abstracts/
_tokens.scss
_functions.scss
_mixins.scss
_index.scss
base/
_reset.scss
_typography.scss
components/
_buttons.scss
_cards.scss
_badges.scss
layout/
_dashboard.scss
themes/
_themes.scss
main.scss
The implementation should keep tokens, reusable abstractions, base styles, layout rules, and components separate. Avoid introducing a dependency merely to demonstrate a feature that Sass already supports.
- Primary technology:
Dart Sass and SCSS - Optional framework:
React with CSS Modules - Required themes:
Light and dark - Required output:
Compiled CSS and documented source
Which architecture best supports a reusable design system?
Implement Tokens, Functions, and Mixins
Begin by defining spacing, color, typography, and breakpoint tokens. Use semantic naming for shared decisions and keep raw values in a centralized location where practical.
Next, implement a spacing function that reads from a map and raises an error for unknown tokens. Add a container mixin that accepts a maximum width and horizontal gutter. Add a focus-ring mixin that ensures interactive components share a consistent keyboard focus treatment.
Keep each abstraction focused. A token should represent a stable value, a function should calculate or retrieve a value, and a mixin should generate a reusable block of CSS.
Compile the source after each architectural step so that errors are identified before additional modules depend on the new API.
// abstracts/_tokens.scss
$spacing: (
sm: 0.5rem,
md: 1rem,
lg: 1.5rem,
xl: 2rem
);
$breakpoints: (
tablet: 48rem,
desktop: 72rem
);
// abstracts/_functions.scss
@use "sass:map";
@use "tokens";
@function spacing($name) {
@if not map.has-key(tokens.$spacing, $name) {
@error "Unknown spacing token: #{$name}";
}
@return map.get(tokens.$spacing, $name);
}
// abstracts/_mixins.scss
@mixin container($max-width: 72rem, $gutter: 1rem) {
width: min(calc(100% - 2 * #{$gutter}), #{$max-width});
margin-inline: auto;
}
@mixin focus-ring($color: #222) {
&:focus-visible {
outline: 3px solid $color;
outline-offset: 3px;
}
}@use and validates requested spacing keys. The mixins module provides reusable layout and accessibility patterns.
Place each commented file in the corresponding directory. Sass resolves the relative module paths during compilation. This example illustrates the core abstractions; additional semantic color tokens and typography scales should be added for the full project.What is the benefit of validating a spacing token inside the capstone function?
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?
Test, Review, and Deploy the Design System
Finish the project by compiling the stylesheet in both development and production modes. Inspect the generated CSS and confirm that selectors, media queries, theme tokens, and component variants behave as expected.
Test the dashboard at narrow, intermediate, and wide viewport sizes. Check keyboard navigation, visible focus, contrast, text wrapping, grid overflow, and component behavior when content is longer than expected.
Run the configured linter and ensure that the production build fails when Sass compilation fails. Review source maps, generated asset sizes, and the deployment path for compiled CSS.
Definition of done
- All required modules compile without errors.
- Design tokens are centralized and consistently consumed.
- Button and badge variants are generated from controlled maps.
- Light and dark themes work without recompilation.
- Responsive layouts work across the intended viewport range.
- Interactive elements have visible keyboard focus.
- The generated CSS is inspected and unnecessary output is removed.
- The build process is repeatable locally and in CI.
- The project README explains installation, development, compilation, and production deployment.
npm install
npx sass --watch src/scss:public/css
npx sass --no-source-map --style=compressed src/scss/main.scss public/css/main.css
npx stylelint "src/scss/**/*.scss"- The compiled stylesheet is the artifact that must be validated for production.
- Design tokens and Sass modules help establish a maintainable styling architecture.
- CSS custom properties support runtime theme switching.
- Automated compilation and linting complement browser-based accessibility and responsive testing.
- A successful capstone should demonstrate both reusable source code and predictable generated CSS.
Which combination provides the strongest validation before deploying the Sass design system?