Button

A trigger that initiates an action. Five variants — primary, secondary, ghost, critical, link — each with its own emphasis and use context.

Button — Code

The substrate's component recipes are framework-agnostic HTML+CSS+ARIA bundles. Every framework consumes the same source.

Get the recipe

Via shadcn-compatible CLI

The substrate exposes a shadcn-registry-compatible endpoint at https://design.pointsav.com/r/. AI codegen tools — v0, Cursor, Claude Code, Windsurf — and the shadcn CLI use the same endpoint:

npx shadcn add https://design.pointsav.com/r/button.json

This installs the button recipe into <your-project>/components/ui/button.*.

Via Model Context Protocol

The substrate's MCP server (at https://design.pointsav.com/mcp) exposes:

{
  "method": "get_component_recipe",
  "params": { "name": "button", "theme": "pointsav-brand" }
}

AI agents query this at decode time; the response is a complete recipe (HTML, CSS, ARIA, tokens consumed) plus the resolved token values for the requested theme.

Via direct HTTP

Machine-readable JSON:

curl https://design.pointsav.com/api/components/button.json

DTCG-format token subset:

curl -H "Accept: application/design-tokens+json" \
  https://design.pointsav.com/api/tokens/component/button.dtcg.json

Via Git

Customers running their own substrate fork the dtcg-vault/components/button/ directory in the pointsav-design-system Git repository.

HTML + CSS recipe

<button type="button" class="ps-btn ps-btn--primary">
  <span class="ps-btn__label">Save changes</span>
</button>
.ps-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ps-space-3, 8px);
  min-height: 2.5rem;
  padding: 0 var(--ps-space-5, 16px);
  border: 0;
  border-radius: var(--ps-corner-2, 4px);
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.43;
  cursor: pointer;
  transition: background-color
              var(--ps-speed-2, 120ms)
              var(--ps-ease-utility, cubic-bezier(.2,0,.4,1));
  white-space: nowrap;
}

.ps-btn:focus-visible {
  outline: 2px solid var(--ps-focus-ring, #234ed8);
  outline-offset: 2px;
}

.ps-btn--primary {
  background-color: var(--ps-interactive-primary, #234ed8);
  color: var(--ps-ink-on-interactive, #fff);
}

.ps-btn--primary:hover {
  background-color: var(--ps-interactive-primary-hover, #173ab1);
}

The full recipe (all four variants) is at the registry endpoint above.

React adapter (community)

function Button({ variant = 'primary', children, ...props }) {
  return (
    <button
      type="button"
      className={`ps-btn ps-btn--${variant}`}
      {...props}
    >
      <span className="ps-btn__label">{children}</span>
    </button>
  );
}

Vue adapter (community)

<template>
  <button type="button" :class="['ps-btn', `ps-btn--${variant}`]">
    <span class="ps-btn__label"><slot /></span>
  </button>
</template>

<script setup>
defineProps({ variant: { type: String, default: 'primary' } });
</script>

Other framework adapters

The substrate's recipe model is framework-agnostic. Adapters for Svelte, SolidJS, Angular, Web Components, Astro, and server- rendered (Rust/Go/PHP/Python) targets are contributor work. The recipe is the source; the adapter is the consumption path.