Foundational container for creating structured layouts

import { CdrSurface, CdrSurfaceSelection, CdrSurfaceNavigation } from '@rei/cedar'

The surface component is Cedar's highly flexible container which acts as a foundational layer for grouping content and interactive elements. It provides designers and developers with a broad set of styling and layout options to customize aspects like elevation, background, borders, and layout flexibility.

Use surface as a starting point for constructing more specific components such as cards, tiles, and action-driven elements. As a building block, it can adapt to various use cases.

While surface offers a wide range of customization options, make sure to use its specialized variants first whenever appropriate. These variants are built on surface's root pattern but include built-in design decisions for specific use cases, like selection, navigation, and actions.

VariantPurposeStates
SelectionFor building interactive user selection elements that have a checked state.Checked, disabled, loading, and active states
NavigationFor building navigational containers that direct users to other pages or sections.Rest, hover, active, focused, and disabled states
Controls (Coming soon)For building buttons stylized for users to take an action.
  • Surfaces are solid: They represent tangible layers in the visual hierarchy and do not pass through or overlap one another in terms of elevation
  • Surfaces are nestable: You can nest surfaces within one another to create complex layouts, but they maintain their individual properties such as elevation and background
  • Surfaces are draggable: You can make surfaces draggable to enable user interaction (e.g., for sortable grids or modifiable UI layouts)
  • Surfaces are clickable: With the appropriate child components, surfaces can act as clickable zones, but it's important to define these interactions clearly using the correct components (e.g., surface navigation or surface controls)
  • Surfaces do not elevate through other surfaces: Surfaces maintain their position in the visual hierarchy, respecting the elevation levels of surrounding elements
  • Surfaces maintain separation: Surfaces are designed to keep content separated visually, ensuring clear distinctions between layered UI elements

When to use

  • Needing a purely visual or non-interactive container
  • Solving for a use case that doesn't have a specialized surface variant or component
  • Displaying non-interactive, static content in a container
  • Customizing patterns to meet specific requirements of your interaction model

When not to use

  • Solving for a use case that already has a specialized variant or component that meets your interaction pattern
  • Working with complex interaction-driven elements. Instead, look for a dedicated component using a surface variation with built-in behaviors
  • Start with surface when necessary, but first seek more specialized components to fit the interaction pattern you need. Surface provides the most flexibility but is not opinionated about its use. This makes it less suitable for cases requiring clear interaction models
  • Use interaction-specific variants whenever possible. Variants like surface selection and surface navigation are optimized for their use cases and ensure consistent behavior across Cedar interfaces
  • Keep surface for visual-only use cases when no interaction is required. Surface is perfect for cases where you need to manage elevation, background layers, or borders without any interaction

Surface selection acts as a variation of a checkbox/radio. It's used to build components where selection is the primary user interaction. It provides specialized styles and behavior for checked, disabled, and active states.

Components using surface selection:

Fulfillment tile: Displays a composed selection option and provides feedback with optional icons

Usage

When to use

  • Displaying mixed UI elements when using checkbox or radio options
  • Needing a loading option for a checkbox or radio
  • Requiring consistent selection patterns (like multi-select grids or lists)
  • Inside of a radio or checkbox group

When not to use

  • Building a typical form. Instead, use a radio or checkbox
  • Needing only a single line of text for a given selection
  • Presenting a standalone option without other selections available. Instead, use switch

Surface navigation is a specialized variant designed for navigational elements. It provides comprehensive state management for different interaction states (rest, hover, active, focused, and disabled), allowing for fine-grained control over the component's appearance in each state.

When to use

  • Creating clickable areas that navigate to other pages or sections
  • Building navigation menus or grids
  • Designing interactive cards that link to content
  • Implementing tiles with different visual states based on user interaction

When not to use

  • Building form elements or selection controls
  • Creating standalone buttons (use button instead)
  • Implementing non-navigational interactive elements
  • Using for purely decorative purposes without navigation intent

What Cedar provides

Each variant of surface is designed to provide accessible interaction patterns, not just visual compliance:

  • Surface selection includes ARIA attributes and communicates states like disabled and checked effectively to assistive technologies
  • Surface navigation provides clear keyboard navigation, so focus and hover states are distinct and accessible
  • Surface controls (coming soon) ensures focus and press states are highly visible, providing clear interaction feedback to all users, including those with disabilities

Development responsibilities

When using surface as a fallback, implement the appropriate ARIA roles. Also ensure keyboard and screen reader accessibility where relevant.

Surface selection

When using the Surface selection component, here's what you are responsible for:

  • Always group within a radio group if used with a radio role. The group should be properly labled (see implementation).
  • Ensure the content within the component has text, which may be screen reader only. Alternatively, provide an aria-labelledby attribute to link a label
  • Add a tabindex="0" prop when appropriate (most of the time this is true)

Surface navigation

When using the Surface navigation component, here's what you are responsible for:

  • Ensure proper semantic HTML is used within the component (typically using anchor tags for navigation)
  • Provide clear, descriptive text for the navigation destination
  • Maintain sufficient color contrast in all interaction states (rest, hover, active, focused, disabled)
  • Test keyboard navigation to ensure focus states are clearly visible
  • Consider adding aria-current attributes when appropriate to indicate the current page or section

General surface as a fallback

<CdrSurface> 
  <CdrBody>This is a default surface</CdrBody> 
</CdrSurface>

Radio

Use the Surface selection component within a radio group and include a label.

<div id="radio-label">
  How would you like to receieve your order?
</div>
<div
  role="radiogroup"
  aria-labelledby="radio-label"
>
  <CdrSurfaceSelection
    tabindex="0"
    role="radio"
    :checked="orderPreference === 'pickup'"
    @click="orderPreference = 'pickup'"
  >
    <CdrText>Pick up</CdrText>
    <IconCheckFill v-if="orderPreference === 'pickup'" />
  </CdrSurfaceSelection>
  ...
</div>

Checkbox

Use the Surface Selection component as a checkbox. If the content inside does not provide an adequate description, then include a label.

<div id="gift-wrapped-label">
  Would you like your order gift wrapped?
</div>
<CdrSurfaceSelection
  tabindex="0"
  role="checkbox"
  :checked="giftWrapped"
  aria-labelledby="gift-wrapped-label"
  @click="giftWrapped = !giftWrapped"
>
  <CdrText>Gift wrap</CdrText>
  <IconCheckFill v-if="giftWrapped" />
</CdrSurfaceSelection>

Card

Use the Surface Navigation component as a card and the Surface Navigation Link component as a card link.

<CdrSurfaceNavigation v-bind="props" class="card">
  <CdrSurfaceNavigationLink href="#">
    Link
  </CdrSurfaceNavigationLink>
</CdrSurfaceNavigation>

When using CdrSurface or CdrSurfaceSelection in a TypeScript application, we recommend importing the surface or surfaceSelection interface, respectively, from the library. These interfaces allow typed options passed to the component.

ParentComponent.vue

<script setup lang="ts">
import {
  CdrSurface
  CdrSurfaceSelection,
  type surface,
  type surfaceSelection
} from '@rei/cedar'

const surfaceExample: surface = {
  background: 'secondary',
  withBorder: true,
};

const surfaceSelectionExample: surfaceSelection = {
  checked: false,
  modifier: 'primary',
  role: 'checkbox',
  loading: false,
  disabled: true,
};

</script>

<template>
  <main>
    <CdrSurface v-bind="surfaceExample">
      <CdrSurfaceSelection v-bind="surfaceSelectionExample">
        ...
      </CdrSurfaceSelection>
    </CdrSurface>
  </main>
</template>

CdrSurface

Props

NameTypeDefault
background

Adds in a background color based on the current palette's tokens.

union
borderColor

Specifies a border color based on the token options within Cedar.

union
borderStyle

Specifies a border style based on the token options within Cedar.

union
borderWidth

Specifies a border width based on the token options within Cedar.

union
borderRadius

Adds in a border radius based on the token options within Cedar.

union
boxShadow

Adds a shadow based on the token options within Cedar.

union
tag

Determines which HTML tag to use.

Tag'div'
palette

Defines a palette for the component's style variations.

union

Slots

Name
default

CdrSurfaceSelection

Props

NameTypeDefault
palette

Defines a palette for the component's style variations.

union
tag

Determines which HTML tag to use.

Tag'div'
boxShadow

Adds a shadow based on the token options within Cedar.

union
borderRadius

Adds in a border radius based on the token options within Cedar.

union
borderWidth

Specifies a border width based on the token options within Cedar.

union
borderStyle

Specifies a border style based on the token options within Cedar.

union
borderColor

Specifies a border color based on the token options within Cedar.

union
background

Adds in a background color based on the current palette's tokens.

union
checked

Determines if the surface is in a checked state. Adds an `aria-checked` attribute.

boolean
disabled

Determines if the surface is in a disabled state.

boolean
loading

Determines if the surface is in a loading state.

boolean
role

Determines the ARIA role of the surface. Typically 'radio' or 'checkbox'.

string'checkbox'
layout

Layout props that will be merged with selection defaults.

Layout

Slots

Name
default

loading

CdrSurfaceNavigation

Props

NameTypeDefault
background

Adds in a background color based on the current palette's tokens.

union
borderColor

Specifies a border color based on the token options within Cedar.

union
borderStyle

Specifies a border style based on the token options within Cedar.

union
borderWidth

Specifies a border width based on the token options within Cedar.

union
borderRadius

Adds in a border radius based on the token options within Cedar.

union
boxShadow

Adds a shadow based on the token options within Cedar.

union
tag

Determines which HTML tag to use.

Tag'div'
palette

Defines a palette for the component's style variations.

union

Slots

Name
default