Tessera UI

Components

Button

Triggers an action. Press it with a mouse, a finger, Enter or Space.

The preview needs JavaScript. The code is in the Code tab.

Button-0.tess
<template>
  <div>
    <Button>Primary</Button>
    <Button tone="neutral" emphasis="outline">Neutral</Button>
  </div>
</template>

Installation

npx @pixelscriptio/tessera add Button
pnpm exec tessera add Button
yarn tessera add Button
bunx @pixelscriptio/tessera add Button
  • Works with Tessera 0.9.0 or newer.
  1. Copy and paste the code into your project

    Put it in system/components.

    system/components/Button.tess
    <contract>
    {
      "name": "Button",
      "role": "button",
      "description": "Triggers an action. Press it with a mouse, a finger, Enter or Space.",
      "since": "0.1.0",
      "parts": ["root", "icon", "label"],
      "variants": {
        "tone": ["primary", "neutral", "danger"], // first value is the default
        "size": ["sm", "md", "lg"],
        "emphasis": ["solid", "outline", "ghost"]
      },
      "states": ["hover", "focus-visible", "pressed", "disabled"],
      "behavior": "press",
      "slots": {
        "default": "label content",
        "icon": "optional leading icon"
      },
      "events": {
        "press": "fired on click, Enter, or Space, with { source: 'pointer' | 'keyboard' | 'virtual' }"
      },
      "preview": {
        "slots": {
          "default": "Save changes"
        }
      }
    }
    </contract>
    
    <script>
    const { disabled, type } = props({ disabled: false, type: 'button' })
    </script>
    
    <template>
      <button class="root" :type="type" :disabled="disabled" @press="emit('press', $event)">
        <span class="icon"><slot name="icon" /></span>
        <span class="label"><slot /></span>
      </button>
    </template>
    
    <style>
    .root {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: $space.2;
      padding: $space.2 $space.4;
      border: 1px solid transparent;
      border-radius: $radius.md;
      background: $color.action.primary.bg;
      color: $color.action.primary.fg;
      cursor: pointer;
      transition-duration: $motion.duration.fast;
    
      &:hover {
        background: $color.action.primary.bg-hover;
      }
    
      &:focus-visible {
        outline: 2px solid $color.focus.ring;
        outline-offset: 2px;
      }
    
      &:disabled,
      &[aria-disabled='true'] {
        opacity: $opacity.disabled;
        cursor: not-allowed;
      }
    
      &[data-size='sm'] {
        padding: $space.1 $space.2;
      }
    
      &[data-size='lg'] {
        padding: $space.3 $space.6;
      }
    
      &[data-tone='neutral'] {
        background: $color.surface.raised;
        color: $color.text.default;
      }
    
      &[data-tone='neutral']:hover {
        background: $color.surface.hover;
      }
    
      &[data-tone='danger'] {
        background: $color.action.danger.bg;
        color: $color.action.danger.fg;
      }
    
      &[data-tone='danger']:hover {
        background: $color.action.danger.bg-hover;
      }
    
      &[data-emphasis='outline'],
      &[data-emphasis='ghost'] {
        background: transparent;
        color: $color.action.primary.text;
      }
    
      &[data-emphasis='outline'] {
        border-color: currentColor;
      }
    
      &[data-emphasis='outline'][data-tone='neutral'],
      &[data-emphasis='ghost'][data-tone='neutral'] {
        color: $color.text.default;
      }
    
      &[data-emphasis='outline'][data-tone='danger'],
      &[data-emphasis='ghost'][data-tone='danger'] {
        color: $color.action.danger.text;
      }
    
      &[data-emphasis='outline']:hover,
      &[data-emphasis='ghost']:hover {
        background: $color.surface.raised;
      }
    }
    
    .icon {
      display: inline-flex;
    }
    
    .icon:empty {
      display: none;
    }
    </style>
    
  2. Check your design tokens

    Your design system needs these. tessera add reports the ones that are missing; by hand, run npx @pixelscriptio/tessera check.

    color.action.danger.bg color.action.danger.bg-hover color.action.danger.fg color.action.danger.text color.action.primary.bg color.action.primary.bg-hover color.action.primary.fg color.action.primary.text color.focus.ring color.surface.hover color.surface.raised color.text.default motion.duration.fast opacity.disabled radius.md space.1 space.2 space.3 space.4 space.6

Usage

Using Button

Use a button for an action, and a Link to go somewhere.

  • Say what happens: "Save changes", not "OK".
  • One primary button per view.
  • It is a plain button. Set type="submit" for the button that sends a Form.

The preview needs JavaScript. The code is in the Code tab.

Button-0.tess
<template>
  <div>
    <Button>Primary</Button>
    <Button tone="neutral" emphasis="outline">Neutral</Button>
  </div>
</template>

API reference

Variants

VariantValues
toneprimary default neutral danger
sizesm default md lg
emphasissolid default outline ghost

Slots

SlotContent
defaultlabel content
iconoptional leading icon

Events

EventWhen
pressfired on click, Enter, or Space, with { source: 'pointer' | 'keyboard' | 'virtual' }

Anatomy

Rolebutton
Behaviorpress
Partsroot icon label
Stateshover focus-visible pressed disabled
Since0.1.0

Design tokens it uses

Your design system needs these. tessera add checks that it has them, and can add the ones it lacks.

color.action.danger.bg color.action.danger.bg-hover color.action.danger.fg color.action.danger.text color.action.primary.bg color.action.primary.bg-hover color.action.primary.fg color.action.primary.text color.focus.ring color.surface.hover color.surface.raised color.text.default motion.duration.fast opacity.disabled radius.md space.1 space.2 space.3 space.4 space.6

Checksum

9205bc828f63b9642398a6cd3ddc4250f0bbd00ca6a96a89f8ac2db0532f333f