fulfillment tile

Selection variant of CdrSurfaceSelection with additional interactive states

import { CdrFulfillmentTile } from '@rei/cedar'

The fulfillment tile shows a checked state with descriptive content. It extends the surface selection component, providing a set of features intended for product, checkout, and search pages.

This component comes with styles for checked, disabled, loading, and active states. It also provides:

  • A layout for inner elements
  • A content component for styling text below the header
  • An icon component that can be used in the header
  • A header component

These parts allow Cedar users to build a custom version of the fulfillment tile.

All dos and don'ts from surface selection apply, but with some extra criteria:

When to use

  • The ability to select a surface is needed, but with a more structured approach to the header and lower content
  • When a status icon is helpful within a surface selection

When not to use

  • Displaying mixed media, like a color swatch. The surface selection component may be more appropriate for these types of designs

Make sure fulfillment tiles:

  • Convey the current state at all times (checked, disabled, active, loading)
  • Serve a single purpose for a changing an option. It should not contain links or other interactive elements
  • Are part of a radio group if used with a radio role. The group should be properly labled (see implementation)

Loading

When the loading prop is true, all content in the body and footer slots will have the opacity animated to 0, hiding the content. At this point, the loading slot will appear, while retaining the same size of the component. You can provide a loading slot, or use the default, which is a single CdrSkeletonBone line. The header slot will always display.

Disabled

When a selection is disabled, it will not emit any events.

Orientation

Inside of the component is CdrLayout, a grid that comes with a recommended gap.

Body

The body content is for displaying any lengthier text that needs to be part of the tile. It will attempt to stretch to use any extra space within the tile.

The footer content is for text that is slightly larger than the body content and has a bit more prominence.

What Cedar provides

  • Adds the aria-checked attribute at all times
  • Adds the disabled attribute

Development responsibilities

When using this component, here's what you are responsible for:

  • Always group within a radio group if used with a radio role. Make sure the group is properly labled (see implementation)
  • Add a tabindex="0" prop when appropriate (most of the time this is true)

Radio

Use the component within a radio group and include a label. Here is a simple example of how you can use the fulfillment tile on the product page:

<div id="radio-label">
  How would you like to receieve your order?
</div>
<div
  role="radiogroup"
  aria-labelledby="radio-label"
>
  <CdrFulfillmentTile
    tabindex="0"
    role="radio"
    :checked="orderPreference === 'pickup'"
    @click="orderPreference = 'pickup'"
  >
    <template #icon-right>
      <CdrFulfillmentTileIcon
        v-if="orderPreference === 'pickup'"
        type="success"
      >
        <IconCheckFill  />
      </CdrFulfillmentTileIcon>
    </template>
    <template #header>Pick up</template>
    <template #body>At San Diego</template>
  </CdrFulfillmentTile>
  <CdrFulfillmentTile
    tabindex="0"
    role="radio"
    :checked="orderPreference === 'ship'"
    @click="orderPreference = 'ship'"
  >
    <template #icon-right>
      <CdrFulfillmentTileIcon
        v-if="orderPreference === 'ship'"
        type="success"
      >
        <IconCheckFill  />
      </CdrFulfillmentTileIcon>
    </template>
    <template #header>Ship it</template>
  </CdrFulfillmentTile>
</div>

Checkbox

Use the component as a checkbox. If the content inside does not provide an adequate description, then include a label. Here is an example of how you can use the fulfillment tile on the search page:

<h2>Fulfillment methods available:</h2>
<div role="group">
  <div>
    <CdrFulfillmentTile
      :checked="methods.includes('store')"
      role="checkbox"
      tabindex="0"
      @click="toggleMethod('store')"
    >
      <template #icon-left>
        <div :class="{ 'example__icon': true, 'example__icon--checked': methods.includes('store') }" />
      </template>
      <template #header>Store Pickup (32)</template>
      <template #footer>
        In stock at
        <strong>Encinitas</strong>
      </template>
    </CdrFulfillmentTile>
    <CdrButton modifier="link">
      Change store
    </CdrButton>
  </div>
  <CdrFulfillmentTile
    :checked="methods.includes('ship')"
    role="checkbox"
    tabindex="0"
    @click="toggleMethod('ship')"
  >
    <template #icon-left>
      <div :class="{ 'example__icon': true, 'example__icon--checked': methods.includes('store') }" />
    </template>
    <template #header>Ship to address (32)</template>
  </CdrFulfillmentTile>
</div>

<style lang="scss" scoped>
@import '@rei/cdr-tokens/dist/rei-dot-com/scss/cdr-tokens.scss';

.example {
  &__icon {
    display: inline-block;
    vertical-align: middle;
    flex: 0 0 auto;
    width: 1.8rem;
    height: 1.8rem;
    margin: $cdr-space-eighth-x;
    fill: inherit;
    border-radius: $cdr-radius-round;
    border: $cdr-space-sixteenth-x solid #2e2e2b;

    &--checked {
      border-width: 0.7rem;
    }
  }
}
</style>

When using CdrFulfillmentTile in a TypeScript application, we recommend importing the surfaceSelection interface from the library if you want fine-grained control over the options passed to the component.

ParentComponent.vue

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

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

</script>

<template>
  <main>
    <CdrFulfillmentTile v-bind="example">
      ...
    </CdrFulfillmentTile>
  </main>
</template>

CdrFulfillmentTile

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'soft'
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
icon-left

Icon to display on the left of the header.

header

Header content that is still visible during loading.

icon-right

Icon to display on the right of the header.

body

Default font size is a step down. Placed just below the header.

footer

Footer content will be at the bottom of the component.