Staaarter

Billing Tax Form Upload

A tax document upload block with a tax-year picker, a dropzone-style control that accepts a click or a real drag-and-drop file, and a status upload button. Below the upload area, an optional history list shows previously submitted forms with a Verified, Pending, or Expired status badge. Built for billing settings pages where customers need to keep W-8 or W-9 forms current across tax years.

By Staaarter Team
Billing
Updated May 24, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its badge, button dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-tax-form-upload.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing138.tsx instead.

Usage

The file also exports billing138Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing138, billing138Demo } from "@/components/blocks/billing/billing138";

export default function Page() {
  return <Billing138 {...billing138Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Upload your tax form"Form heading.
descriptionstring(see source)Supporting line under the heading.
taxYearsstring[]noneYears offered in the tax-year picker, rendered as toggle chips in the order given.
defaultTaxYearstringtaxYears[0]Which tax year is selected on first render.
existingFormsTaxFormRecord[][]Previously submitted forms shown as a history list below the uploader. Omit or pass an empty array to hide the section entirely.
submitLabelstring"Upload form"Label on the upload button.
classNamestringnoneExtra classes for the outer container.

Types

interface TaxFormRecord {
  id: string;
  formType: string;
  taxYear: string;
  status: "Verified" | "Pending" | "Expired";
  uploadedDate: string;
}

Behavior notes

  • The dropzone accepts both a click, which opens a hidden native file input, and a real HTML5 drag-and-drop, tracked with local isDragging state for the highlighted border.
  • No upload progress is simulated. Selecting or dropping a file just records its name in state, submitting shows a fixed roughly 800ms loading state and then a confirmation, there's no fake progress bar or timer-driven percentage.
  • The upload button stays disabled until both a tax year is selected and a file is chosen.
  • Status badges for existing forms map Verified, Pending, and Expired to their own icon and color internally; there's no prop for custom statuses, add a case to the component's internal maps to extend the union.
  • The existing-forms section only renders when existingForms is non-empty, so the block works standalone for a first-time upload with no history yet.

Frequently asked questions