surface
Foundational container for creating structured layouts
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.
Variant | Purpose | States |
---|---|---|
Selection | For building interactive user selection elements that have a checked state. | Checked, disabled, loading, and active states |
Navigation | For 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
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
Name | Type | Default |
---|---|---|
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
Name | Type | Default |
---|---|---|
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
Name | Type | Default |
---|---|---|
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 |