Components

Button

Buttons start an action. Flint has four: primary, secondary, danger and text.

CSS

For Astro, EJS and plain HTML. These rules read only component tokens.

HTML
<button type="button" class="flint-btn flint-btn--primary">Save trip</button>
<button type="button" class="flint-btn flint-btn--secondary">Add stop</button>
<button type="button" class="flint-btn flint-btn--danger">Delete trip</button>
<button type="button" class="flint-btn flint-btn--text">Skip for now</button>
CSS
.flint-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-8);
  min-height: var(--button-height); padding: 0 var(--space-16);
  border: 1px solid transparent; border-radius: var(--button-radius);
  font: 700 var(--font-size-sm) / 1.2 var(--font-sans); cursor: pointer;
}
.flint-btn:focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: var(--focus-ring-offset); }
.flint-btn--primary { background: var(--button-primary-bg); color: var(--button-primary-fg); }
.flint-btn--primary:hover { background: var(--button-primary-bg-hover); }
.flint-btn--secondary { background: var(--button-secondary-bg); color: var(--button-secondary-fg); border-color: var(--button-secondary-border); }
.flint-btn--secondary:hover { background: var(--button-secondary-bg-hover); }
.flint-btn--danger { background: var(--button-danger-bg); color: var(--button-danger-fg); }
.flint-btn--danger:hover { background: var(--button-danger-bg-hover); }
.flint-btn--text { background: transparent; color: var(--button-text-fg); }
.flint-btn--text:hover { background: var(--button-text-bg-hover); }
.flint-btn:disabled { background: var(--button-disabled-bg); color: var(--button-disabled-fg); border-color: transparent; cursor: not-allowed; }
.flint-btn--secondary:disabled { border-color: var(--button-disabled-border); }
.flint-btn--text:disabled { background: transparent; }

MUI

React (MUI)
import Button from '@mui/material/Button';

<Button variant="contained">Save trip</Button>
<Button variant="outlined">Add stop</Button>
<Button variant="contained" color="error">Delete trip</Button>
<Button variant="text">Skip for now</Button>

Known gap

The MUI theme does not apply the secondary and disabled button tokens yet, and its buttons are 36px tall instead of 40px (ASDS-44).

shadcn/ui

The Flint version of the shadcn component. Same API as upstream; every value reads a Flint token.

components/ui/button.jsx
// shadcn/ui Button, restyled to Flint. Same API as upstream (variant, asChild); every color,
// size and focus value reads a Flint component token instead of shadcn's defaults.
// Changed from upstream: no opacity-50 disabled state (disabled has its own tokens), and the
// focus ring is Flint's solid 2px ring instead of a 50% transparent ring.
import { Slot } from '@radix-ui/react-slot';
import { cva } from 'class-variance-authority';
import { cn } from '../cn';

const buttonVariants = cva(
  'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--button-radius)] min-h-[var(--button-height)] px-4 text-sm font-bold transition-colors cursor-pointer border border-transparent outline-none focus-visible:[outline:var(--focus-ring-width)_solid_var(--focus-ring-color)] focus-visible:[outline-offset:var(--focus-ring-offset)] disabled:cursor-not-allowed disabled:bg-[var(--button-disabled-bg)] disabled:text-[var(--button-disabled-fg)]',
  {
    variants: {
      variant: {
        default: 'bg-[var(--button-primary-bg)] text-[var(--button-primary-fg)] hover:bg-[var(--button-primary-bg-hover)]',
        secondary: 'border-[var(--button-secondary-border)] bg-[var(--button-secondary-bg)] text-[var(--button-secondary-fg)] hover:bg-[var(--button-secondary-bg-hover)] disabled:border-[var(--button-disabled-border)]',
        destructive: 'bg-[var(--button-danger-bg)] text-[var(--button-danger-fg)] hover:bg-[var(--button-danger-bg-hover)]',
        ghost: 'bg-transparent text-[var(--button-text-fg)] hover:bg-[var(--button-text-bg-hover)] disabled:bg-transparent',
      },
    },
    defaultVariants: { variant: 'default' },
  },
);

export function Button({ className, variant, asChild = false, ...props }) {
  const Comp = asChild ? Slot : 'button';
  return <Comp data-slot="button" className={cn(buttonVariants({ variant }), className)} {...props} />;
}

export { buttonVariants };

SwiftUI

SwiftUI
Button("Save trip", action: save)
  .flintText(Flint.Typography.labelButton)
  .foregroundStyle(Flint.Component.buttonPrimaryFg)
  .padding(.horizontal, Flint.Space.s16)
  .frame(minHeight: Flint.Target.touch)
  .background(Flint.Component.buttonPrimaryBg,
              in: RoundedRectangle(cornerRadius: Flint.Component.buttonRadius))

A ready-made SwiftUI button is moving into the Flint package (ASDS-38). Until then, build it from the component tokens as above.