Skip to content
Recursica

Layers

The Recursica Layer System is a core mechanism for organizing visual depth, nesting structures, and content stacking. By arranging components, such as cards, panels, fields, and modals, into structured layers, the system automatically calculates the appropriate text color, border styling, and element backgrounds to maintain a consistent and readable interface.

Each layer’s properties (surface color, text color, border, elevation, padding) are defined as design tokens following the W3C Design Tokens Community Group format, authored in Theme Forge and exported alongside the rest of the theme. A component never hardcodes “what layer 2 looks like”; it reads the layer’s tokens, so a re-themed export restyles every layer everywhere. See Architecture for how those tokens are structured.

Core Layers and Stacking Rules

The system establishes four sequential layers, from Layer 0 (base) to Layer 3 (overlay). To guarantee clean contrast and interface legibility, elements must stack sequentially:

  • Layer 0 (Base Background): The main canvas background of the application window. It is flat and serves as the container for all layout structures.
  • Layer 1 (Surfaces): Primary containers and panels resting directly on the canvas background. Examples include sidebars, dashboard grids, and content cards.
  • Layer 2 (Nested Fields): Elements nested inside Layer 1 surfaces. Examples include input fields, list headers, table rows, and inner cards.
  • Layer 3 (Overlays): Transient, high-priority elements that float over nested components. Examples include dropdown menus, select fields, and tooltip overlays.

How a layer is applied

A layer is not a class or a component wrapper. It is a single data attribute, and the CSS cascade does the rest.

<html data-recursica-theme="light">      <!-- layer 0 by default -->
  <section data-recursica-layer="1">     <!-- a card -->
    <input>                              <!-- resolves layer 1 values -->
    <section data-recursica-layer="2">   <!-- a field group inside it -->
      <input>                            <!-- resolves layer 2 values -->
    </section>
  </section>
</html>

Three rules govern it:

  1. Theme goes on the root, layer goes on a container. Setting data-recursica-theme on <html> is enough for an entire application; layer 0 applies by default, so a page that never sets a layer is already correct.
  2. Descendants inherit until something says otherwise. Everything inside a data-recursica-layer="1" element resolves layer 1 values. A nested element with its own attribute takes over for its own subtree.
  3. Components never name a layer. They use generic variable names like --recursica_ui-kit_components_button_variants_styles_solid_properties_colors_background, and the attribute on an ancestor decides what that resolves to. Matching [data-recursica-layer] in your own component selectors defeats the mechanism.

Every layer redefines every component

A layer block does not only carry that layer’s surface and text. It redefines the entire component set at that depth, which is why the same solid button on a page canvas and inside a modal are not the same color. The component is unchanged; its ancestors are different.

This is also the one gotcha worth remembering: the generic names for layers 1 through 3 exist only inside their layer blocks. An element styled with layer-1 tokens that is not inside a data-recursica-layer="1" ancestor resolves to nothing. Layer 0’s generics resolve at the theme level, which is why the default never fails.

Accessibility and Auto-Contrast

The primary benefit of the Recursica Layer System is built-in accessibility. Component text, icons, and borders automatically adjust their color values relative to the background layer they are placed on.

This ensures that regardless of whether your component is nested in a Layer 1 card or sitting directly on a Layer 0 background, it automatically satisfies WCAG AA contrast standards. This system operates natively across both Light and Dark themes.

Each layer therefore carries two related but distinct kinds of value, and mixing them up is the most common source of a low-contrast bug:

  • Surface and tone values are what an element is filled with, such as layer_1_properties_surface or an interactive element’s tone.
  • Foreground values are what is drawn on top of that fill, such as layer_1_elements_text_color or layer_1_elements_interactive_color. These are the contrast-checked ones, and they are what text, icons, and links must use.

A link painted with an interactive tone instead of an interactive color will render as the button fill, which may be a pale tint that fails AA against the surface behind it.

Alternative Layers

Alternative layers are specialized themes reserved for custom callouts and status signaling, operating outside the normal sequential stacking flow:

  • High Contrast: Highlights critical elements by inverting the theme contrast (e.g., rendering a dark surface in Light Mode). Use sparingly for banners and alerts that demand universal attention.
  • Primary Accent: Applies the brand’s main color scale to a surface (e.g., a persistent header, branding banner, or footer).
  • Status (Alert, Success, Warning): Applies feedback color scales to communicate application states (e.g., red backgrounds for error dialogs or green borders for success indicators).