Skip to main content
The Members Portal uses Bootstrap 5.3 with SCSS customisation, CSS Modules for component-scoped styles, and CSS custom properties for runtime theming. This page explains how these layers work together and how to make changes at each level.

Architecture overview

Styles are compiled into a single CSS bundle. The compilation order in style.scss determines which layer can override which.

Folder structure

All SCSS source files live under src/assets/scss/:

Default colour palette

Default colours are defined in _defaults.scss using the !default flag, which means they can be overridden by any value set before the import:
_variables.scss then derives contrast colours, subtle variants, and border colours from these base values and exports them as a $theme-colors map. Bootstrap uses this map to generate CSS custom properties like --bs-primary, --bs-primary-bg-subtle, etc.

How components are styled

Components use one of three patterns (often combined):

CSS Modules (scoped styles)

Component-specific styles live in a .module.scss file next to the component. Class names are locally scoped at build time so they never leak.
Use CSS custom properties inside .module.scss files to reference theme colours: color: var(--bs-primary);

Bootstrap utility classes

Most layout and spacing is handled with Bootstrap 5 utility classes directly in JSX:
The project extends Bootstrap’s utility API in custom/_utilities.scss with additional helpers such as fixed-pixel heights (h-40px), viewport heights (vh-100), and more.

Global SCSS (unscoped)

Some components import a plain .scss file for global styles. These affect the entire page and are typically used for animation keyframes or third-party library overrides:
Prefer CSS Modules over global imports for new components. Global styles can cause unintended side-effects.

Runtime branding (per-location colours)

Each location can set its own brand colours in the Nexudus dashboard. The portal loads these at runtime through a two-step process:
  1. The client fetches /api/scss-to-css?businessId=<id>&hash=<colorHash>.
  2. The endpoint compiles a virtual SCSS file that overrides $primary, $secondary, etc. before importing the full style.scss.
  3. The compiled CSS is cached in Vercel Blob storage with a hash-based filename.
  4. An edge function serves the cached file with CDN headers for fast delivery.
The virtual SCSS that gets compiled looks like this:
Because _defaults.scss uses !default, the runtime values take precedence.

Dark mode

Dark mode is controlled via the data-bs-theme attribute on the <html> element. The _dark-mode.scss file redefines CSS custom properties when this attribute is set:
Theme switching is managed by the useLayoutContext hook:
The preference is saved to localStorage and restored on load.
When writing component styles, always use CSS custom properties (var(--bs-body-bg)) instead of hard-coded colour values. This ensures your styles work in both light and dark modes.

Extending Bootstrap utilities

Custom utility classes are registered in custom/_utilities.scss using Bootstrap’s utility API. To add a new utility:
This generates classes like .custom-opacity-25, .custom-opacity-50, etc. with responsive variants if you add responsive: true.

Overriding Bootstrap component styles

Bootstrap component customisations live in custom/ as partial SCSS files (e.g., _buttons.scss, _card.scss). These are imported after Bootstrap core, so they can override default styles. To adjust a Bootstrap component:
1

Find the right partial

Look in src/assets/scss/custom/ for an existing file that matches the component (e.g., _buttons.scss for buttons).
2

Add your overrides

Write your SCSS rules in that file. You can use Bootstrap variables and mixins:
3

Verify the import

Make sure the file is imported in style.scss. All existing partials are already imported.

Adding styles to a new component

1

Create a CSS Module file

Add a .module.scss file next to your component:
2

Write scoped styles

3

Import and use in the component

Combine CSS Modules for component-specific layout with Bootstrap utilities for spacing and typography. This keeps styles scoped while reusing the design system.

The _user.scss file

_user.scss is imported last in style.scss and is intended for project-level custom rules that don’t belong to a specific component or Bootstrap override. It currently contains helpers like .sticky-top-20, .no-select, and .disabled-component. Add rules here when you need a global utility that doesn’t fit into Bootstrap’s utility API or a component module.

Key conventions

PracticeRationale
Use CSS Modules for new componentsPrevents style leaking between components
Use var(--bs-*) for coloursEnsures light/dark mode and branding compatibility
Never hard-code colour values in componentsRuntime branding would not apply
Put Bootstrap overrides in custom/Keeps overrides organized and discoverable
Put vendor/library overrides in components/vendor/Separates third-party concerns from project styles
Use !default for new SCSS variablesAllows runtime and theme-level overrides