Skip to content

@vibe-labs/design-components-buttons

Button component tokens, styles, and TypeScript types for the Vibe Design System.

Installation

bash
npm install @vibe-labs/design-components-buttons
css
@import "@vibe-labs/design-components-buttons";
ts
import { ButtonSizes, ButtonVariants, ButtonShapes } from "@vibe-labs/design-components-buttons/types";
import type { ButtonSize, ButtonVariant, ButtonShape, ButtonStyleProps } from "@vibe-labs/design-components-buttons/types";

Contents

Tokens

Component-specific tokens defined in @layer vibe.tokens (file: button.css). Core sizing tokens (--btn-height-*, --btn-px-*, --btn-radius, --btn-font-weight, --btn-font-size-*) are owned by @vibe-labs/design-forms.

Variant Tokens

Each variant defines bg, color, border, hover, and active states:

  • Primary--btn-primary-bg · --btn-primary-color · --btn-primary-border · --btn-primary-hover-bg · --btn-primary-hover-border · --btn-primary-active-bg · --btn-primary-active-border
  • Secondary--btn-secondary-bg · --btn-secondary-color · --btn-secondary-border · --btn-secondary-hover-bg · --btn-secondary-hover-border · --btn-secondary-active-bg
  • Ghost--btn-ghost-color · --btn-ghost-hover-bg · --btn-ghost-active-bg
  • Danger--btn-danger-bg · --btn-danger-color · --btn-danger-border · --btn-danger-hover-bg · --btn-danger-hover-border · --btn-danger-active-bg · --btn-danger-active-border
  • Link--btn-link-color

Other Tokens

TokenDefaultDescription
--btn-loading-spinner-width--spinner-width (2px)Loading spinner border width
--btn-spinner-color--color-accent-contrastSpinner color
--btn-group-overlap--border-width-1Negative margin between grouped buttons

Generated Styles

Component classes generated into @layer vibe.components (file: button.g.css).

Variants

VariantDescription
primaryAccent-colored solid button
secondaryElevated surface with border
ghostTransparent with hover overlay
dangerDanger-colored solid button
linkInline link style, no padding/height

Sizes

sm · md (default) · lg — sizing tokens from @vibe-labs/design-forms.

Shapes

ShapeDescription
defaultStandard --btn-radius — no data-shape attribute needed
circleFull radius (--radius-full) with hover scale(1.1) / active(1.05)

Shape is set via data-shape attribute. The base transition includes transform so shape animations compose cleanly with variant colour transitions.

States

StateDescription
disabledReduced opacity, cursor: not-allowed, no pointer events (also aria-disabled)
data-loadingHides text, shows CSS spinner via ::after pseudo-element
focus-visibleRing via box-shadow using --ring-color / --ring-offset-*

Modifiers

ModifierDescription
data-fullwidth: 100%
data-iconRemoves horizontal padding, aspect-ratio: 1

Button Group

.btn-group — inline flex container that strips inner border radii and overlaps borders between adjacent buttons using --btn-group-overlap.

TypeScript Types

ts
ButtonSizes    // ["sm", "md", "lg"]
ButtonVariants // ["primary", "secondary", "ghost", "danger", "link"]
ButtonShapes   // ["default", "circle"]

type ButtonSize
type ButtonVariant
type ButtonShape

interface ButtonStyleProps {
  variant?: ButtonVariant
  size?: ButtonSize
  shape?: ButtonShape
  loading?: boolean
  full?: boolean
  icon?: boolean
  disabled?: boolean
  color?: string
}

interface ButtonGroupStyleProps { label?: string }

Dist Structure

FileDescription
index.cssBarrel — imports tokens + generated styles
button.cssToken definitions (variant colors, spinner, group)
button.g.cssGenerated component styles
index.js / index.d.tsTypeScript types + runtime constants

Dependencies

Requires @vibe-labs/design-forms (sizing tokens) and @vibe-labs/design (colors, surfaces, transitions, elevation).

Build

bash
npm run build

Usage Guide

Import

css
@import "@vibe-labs/design-components-buttons";
ts
import type { ButtonStyleProps } from "@vibe-labs/design-components-buttons/types";

Variants

Variant

Set data-variant on .btn: primary · secondary · ghost · danger · link

Size

Set data-size on .btn: sm · md (default) · lg

Shape

Set data-shape on .btn: omit for default rounded · circle for fully circular

Boolean flags

  • data-loading — hides label, shows CSS spinner
  • data-full — full-width (width: 100%)
  • data-icon — square icon button (removes horizontal padding, aspect-ratio: 1)
  • disabled or aria-disabled="true" — disabled state

Examples

All variants

html
<button class="btn" data-variant="primary">Save changes</button>
<button class="btn" data-variant="secondary">Cancel</button>
<button class="btn" data-variant="ghost">Learn more</button>
<button class="btn" data-variant="danger">Delete account</button>
<button class="btn" data-variant="link">View details</button>

Sizes

html
<button class="btn" data-variant="primary" data-size="sm">Small</button>
<button class="btn" data-variant="primary">Medium</button>
<button class="btn" data-variant="primary" data-size="lg">Large</button>

Loading state

html
<!-- Spinner replaces text content; aria-busy communicates state -->
<button class="btn" data-variant="primary" data-loading aria-busy="true">
  Saving…
</button>

Icon button (circle shape)

html
<!-- Square icon button -->
<button class="btn" data-variant="ghost" data-icon aria-label="Settings">
  <svg><!-- gear icon --></svg>
</button>

<!-- Circular icon button with scale animation on hover -->
<button class="btn" data-variant="primary" data-shape="circle" data-icon aria-label="Add">
  <svg><!-- + icon --></svg>
</button>

Full-width

html
<button class="btn" data-variant="primary" data-full>Sign in</button>

Button group

html
<!-- Adjacent buttons share borders — inner radii are stripped automatically -->
<div class="btn-group" role="group" aria-label="View mode">
  <button class="btn" data-variant="secondary" aria-pressed="true">List</button>
  <button class="btn" data-variant="secondary">Grid</button>
  <button class="btn" data-variant="secondary">Table</button>
</div>

With Vue

Use @vibe-labs/design-vue-buttons for <SbBtn> and <SbBtnGroup> which accept ButtonStyleProps and forward all states to the correct data attributes.

Vibe