Confirm Button

Usage

Click once to enter the confirming state, then click again to execute. The button cycles through four states: idle, confirming, loading, and success.

'use client'
 
import { ConfirmButton } from '@jamie/ui/confirm-button'
import { CheckIcon, LoaderIcon, TrashIcon } from 'lucide-react'
 
export function ConfirmButtonDemo() {
  return (
    <ConfirmButton
      variant="destructive"
      onConfirm={() => new Promise((resolve) => setTimeout(resolve, 1500))}
    >
      <ConfirmButton.Idle>
        <TrashIcon className="size-4" />
        Delete Recording
      </ConfirmButton.Idle>
      <ConfirmButton.Confirming>
        <TrashIcon className="size-4" />
        Are you sure?
      </ConfirmButton.Confirming>
      <ConfirmButton.Loading>
        <LoaderIcon className="size-4 animate-spin" />
        Deleting...
      </ConfirmButton.Loading>
      <ConfirmButton.Success>
        <CheckIcon className="size-4" />
        Deleted
      </ConfirmButton.Success>
    </ConfirmButton>
  )
}

Variants

Use different button variants for non-destructive confirmation flows.

'use client'
 
import { ConfirmButton } from '@jamie/ui/confirm-button'
import { ArchiveIcon, CheckIcon, LoaderIcon, ShareIcon } from 'lucide-react'
 
export function ConfirmButtonVariantsDemo() {
  return (
    <div className="flex gap-4">
      <ConfirmButton
        variant="outline"
        onConfirm={() => new Promise((resolve) => setTimeout(resolve, 1000))}
      >
        <ConfirmButton.Idle>
          <ShareIcon className="size-4" />
          Share Transcript
        </ConfirmButton.Idle>
        <ConfirmButton.Confirming>
          <ShareIcon className="size-4" />
          Confirm share?
        </ConfirmButton.Confirming>
        <ConfirmButton.Loading>
          <LoaderIcon className="size-4 animate-spin" />
          Sharing...
        </ConfirmButton.Loading>
        <ConfirmButton.Success>
          <CheckIcon className="size-4" />
          Shared
        </ConfirmButton.Success>
      </ConfirmButton>
      <ConfirmButton
        variant="secondary"
        onConfirm={() => new Promise((resolve) => setTimeout(resolve, 1000))}
      >
        <ConfirmButton.Idle>
          <ArchiveIcon className="size-4" />
          Archive Meeting
        </ConfirmButton.Idle>
        <ConfirmButton.Confirming>
          <ArchiveIcon className="size-4" />
          Confirm archive?
        </ConfirmButton.Confirming>
        <ConfirmButton.Loading>
          <LoaderIcon className="size-4 animate-spin" />
          Archiving...
        </ConfirmButton.Loading>
        <ConfirmButton.Success>
          <CheckIcon className="size-4" />
          Archived
        </ConfirmButton.Success>
      </ConfirmButton>
    </div>
  )
}