Componentform1.1 KB gzipZero dependencies

Stamp Field

Approval stamp box with name, date and seal.

Preview

Live Preview
SEP 8, 2026Awaiting stamp

Installation

Tokens guide →

Add to your project via CLI (zero dependencies, code you own):

npx bigbullui add stamp-field

Or install the full npm package:

npm install bigbullui
import { StampField } from "@/components/ui/stamp-field";

<StampField />

Usage guidance

Use Stamp Field when a ticket stub surface needs Approval stamp box with name, date and seal. Keep props minimal and prefer composition with sibling stubs.

Avoid Stamp Field for long form flows or dense data grids where a dedicated layout block fits better.

Source code

stamp-field.tsx

Zero dependencies (only React + utils). Copy and paste directly into your project:

"use client";

import * as React from "react";
import { cn } from "./lib/utils";

export interface StampFieldProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
  approver?: string;
  defaultApprover?: string;
  onApprove?: (approver: string, date: string) => void;
  label?: string;
}

export function StampField({
  approver: controlledApprover,
  defaultApprover = "",
  onApprove,
  label = "Approved by",
  className,
  ...props
}: StampFieldProps) {
  const [inner, setInner] = React.useState(defaultApprover);
  const approver = controlledApprover ?? inner;
  const [stamped, setStamped] = React.useState(false);
  const today = new Date().toLocaleDateString(undefined, { dateStyle: "medium" }).toUpperCase();

  const stamp = () => {
    if (approver.trim().length === 0) return;
    setStamped(true);
    onApprove?.(approver.trim(), today);
  };

  return (
    <div className={cn("w-full rounded-lg border border-border bg-card p-4", className)} {...props}>
      <div className="flex items-center gap-3">
        <input
          value={approver}
          disabled={stamped}
          onChange={(e) => setInner(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "Enter") stamp();
          }}
          placeholder="Approver name"
          aria-label={label}
          className="min-w-0 flex-1 rounded-md border border-border bg-background px-3 py-2 font-mono text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-60"
        />
        <button
          type="button"
          onClick={() => (stamped ? setStamped(false) : stamp())}
          disabled={!stamped && approver.trim().length === 0}
          className="shrink-0 cursor-pointer rounded-md bg-primary px-4 py-2 font-mono text-xs font-bold uppercase text-primary-foreground transition-transform hover:scale-[1.02] active:scale-95 disabled:cursor-not-allowed disabled:opacity-40"
        >
          {stamped ? "Reset" : "Stamp"}
        </button>
      </div>
      <div className="mt-3 flex items-center justify-between border-t border-dashed border-border pt-3">
        <span className="font-mono text-[10px] uppercase tracking-widest text-muted-foreground">
          {today}
        </span>
        <span
          aria-live="polite"
          className={cn(
            "inline-block rounded border-2 px-3 py-1 font-mono text-sm font-bold uppercase tracking-widest transition-all",
            stamped
              ? "rotate-[-6deg] border-accent text-accent"
              : "rotate-[-6deg] border-dashed border-border/60 text-muted-foreground/50",
          )}
        >
          {stamped ? `Approved · ${approver}` : "Awaiting stamp"}
        </span>
      </div>
    </div>
  );
}

Props

PropTypeDescription
approverstringControlled approver name.
onApprove(approver: string, date: string) => voidStamp callback.