Skip to content

Frontend Styling

This guide documents the current styling structure in Easy8 and the conventions we use when writing CSS and SCSS.

Choose the Right Styling Layer

Easy8 has more than one styling layer. Before adding styles, first identify which layer the feature already belongs to.

  • New reusable UI belongs in the Design System under app/frontend/src/design_system/.
  • Existing legacy screens, ERB views, and easy_ui integrations usually keep using the legacy Easy styles under app/frontend/src/shared/stylesheets/easy/.
  • Vuetify skinning and component overrides belong under app/frontend/src/shared/stylesheets/vuetify/ when that override already exists there.
  • Utility classes from Tailwind are available globally and are the usual choice for small layout glue in legacy and easy_ui-era Vue components. See Tailwind Utilities.

Do not move a feature between styling systems just because you are touching it. Extend the existing layer unless you are doing an intentional migration.

Main Locations

  • app/frontend/src/<module>/stylesheets/ - default location for custom styles owned by a frontend module or microapp.
  • app/frontend/src/design_system/**/stylesheets/ - component-local Design System styles.
  • app/frontend/src/design_system/shared/stylesheets/ - Design System shared variables, mixins, functions, and foundations.
  • app/frontend/src/shared/stylesheets/easy/_base.scss - main legacy Easy stylesheet entrypoint.
  • app/frontend/src/shared/stylesheets/easy/_common-assets.scss - shared legacy exports for variables, abstracts, and themes.
  • app/frontend/src/shared/stylesheets/easy/global/ - global rules and foundations.
  • app/frontend/src/shared/stylesheets/easy/patterns/ - legacy UI buckets grouped by usage area.
  • app/frontend/src/shared/stylesheets/easy/themes/ - themes and brand-related output.
  • app/frontend/src/shared/stylesheets/easy/variables/ - legacy Easy variables.
  • app/frontend/src/shared/stylesheets/vuetify/ - Vuetify overrides.
  • app/frontend/src/shared/stylesheets/tailwind/index.css - Tailwind theme and source scanning.

General Rules

  • Keep styles in the same layer as the feature you are editing.
  • Keep selectors as flat as possible. Prefer classes over long descendant chains.
  • Avoid !important unless you are fixing a real override problem that cannot be solved cleanly.
  • Reuse existing variables, mixins, and placeholders before introducing new values or abstractions.
  • Keep feature-specific rules close to the owning component, page, or pattern.
  • Do not add or extend custom styles in Vue <style> blocks, including <style scoped>. Put new declarations in the owning module's external SCSS files. Shared components follow the external stylesheet structure of their owning shared layer.
  • Follow naming already used in the edited area instead of forcing a new naming convention into old code.

Tailwind Utilities

Tailwind v4 is compiled through PostCSS and loaded on every page - the base layout includes vite_stylesheet_tag 'tailwind.css', so utilities are available everywhere without importing anything.

The theme lives in app/frontend/src/shared/stylesheets/tailwind/index.css. It disables Tailwind's own source detection (source(none)) and scans app/frontend/src explicitly, so a class only survives the build if it appears literally in that tree. Do not build class names dynamically (`gap-ms${size}`), because they will be stripped.

What the utilities resolve to

The theme is a bridge to the legacy Easy variables, not to the Design System ones. 183 of its mappings point at --easy__*, and only two at Design System tokens.

--spacing-ms1: var(--easy__spacing--ms-1);   /* gap-ms1, p-ms1, m-ms1 ... */
--color-front: var(--easy__color--front);    /* bg-front, text-front ... */
--color-font-muted: var(--easy__color--text-muted);

That is the deciding factor for which to reach for. There is no --Scale-Size-* or --Content-* utility, so a Design System component styled with utilities silently mixes two token families.

Choosing

Neither option replaces using a Design System component and its props where one fits. For the layout glue left over:

Use When
Tailwind utilities The surrounding module already uses them; the component sits on legacy or easy_ui foundations; a handful of one-off layout declarations.
Module-owned SCSS Custom CSS is clearer than utilities, for example for component states, media or container queries, or substantial layout such as a scrollable feed. Put the rules in app/frontend/src/<module>/stylesheets/, namespace them under the module root class or another unique module-owned class for teleported content, and use the token family established by the module.

Load module styles through the module's existing Vite asset path. For a new microapp, import its SCSS aggregate from the module's JavaScript or TypeScript entrypoint, normally under app/frontend/entrypoints/. For an existing module, extend its current loader and styles/ or stylesheets/ structure, including source main or index imports and standalone stylesheet entrypoints loaded with vite_stylesheet_tag.

SCSS Reuse

The codebase uses modern Sass module syntax with @use and @forward.

  • Use @mixin when the style needs configuration or reusable generated output.
  • Use placeholders with @extend %placeholder for fixed shared declaration groups.
  • Prefer extending placeholders, not concrete HTML selectors or unrelated component classes.
  • When working in legacy Easy styles, look for reusable assets in utils/abstracts/ and shared exports from _common-assets.scss.
  • Many legacy pattern files expose @mixin styles; wire them through the owning entrypoint instead of scattering duplicate imports.

Legacy Easy Styles Structure

The app/frontend/src/shared/stylesheets/easy/ tree is still important, but its folder names should be read as implementation organization, not as a required design methodology.

  • global/ - global foundations and cross-app behavior.
  • patterns/00-elements/ - low-level element styling.
  • patterns/01-fragments/ - reusable legacy fragments.
  • patterns/02-components/ - legacy component-level styling.
  • patterns/03-pages/ - page-specific legacy styling.
  • patterns/04-plugins/ - plugin-specific legacy styling.
  • themes/ - theme output and brand-specific values.
  • utils/abstracts/ - mixins, placeholders, and utility building blocks.
  • variables/ - legacy variables and icon definitions.

The numbered patterns/* folders are historical buckets. Do not use them as a reason to describe new work as Atomic Design. For current frontend architecture, prefer the actual module or component boundary you are editing.

Design System Styles

For new reusable UI:

  • Keep styles next to the Design System component under stylesheets/.
  • Reuse tokens, utilities, and foundations from app/frontend/src/design_system/shared/stylesheets/.
  • Prefer local Design System styling over patching the legacy Easy stylesheet when the component itself owns the behavior.
  • If a Design System component needs legacy compatibility, keep that bridge explicit instead of leaking legacy selectors into unrelated components.

Themes and Branding

Theme and brand customization are documented separately in Theme Configuration and custom branding.

Use that guide for:

  • brand asset overrides,
  • theme CSS variables,
  • brand fonts,
  • custom color maps,
  • client-specific visual customization.