Staaarter

Billing Custom Amount

A custom amount entry block for letting people define their own spend instead of picking a fixed tier. Typing into the input updates an inline error the moment the amount falls outside the allowed range, and a preset row lets people jump straight to common values. Built with shadcn/ui Input and Button components, Lucide icons, and Tailwind CSS.

By Staaarter Team
Billing
Updated April 2, 2026
Docs
Live preview

Docs

Installation

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

npx shadcn add https://staaarter.com/r/billing-custom-amount.json

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

Usage

The file also exports billing43Demo, 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 { Billing43, billing43Demo } from "@/components/blocks/billing/billing43";

export default function Page() {
  return <Billing43 {...billing43Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Add funds"Block heading.
descriptionstring"Enter any amount to top up your balance."Supporting text under the heading.
presetsnumber[][25, 50, 100, 250]Quick-select amounts rendered as pill buttons below the input.
minnumber5Smallest amount the input accepts before showing an error.
maxnumber5000Largest amount the input accepts before showing an error.
currencySymbolstring"$"Symbol shown as the input prefix and in preset labels.
defaultAmountnumber50Amount the input is seeded with on first render.
creditsPerDollarnumbernoneWhen set, shows a converted credit total under the input, amount multiplied by this rate.
ctaLabelstring"Add funds"Label on the submit button, the current amount is appended to it once valid.
classNamestringnoneExtra classes for the outer container.

Behavior notes

  • The typed value is a controlled string, not a number, filtered on every keystroke by a regex that allows digits and up to two decimal places so the field never holds invalid characters.
  • Validation runs on every render: an empty field, a value below min, or a value above max each show a distinct inline error and disable the submit button.
  • Clicking a preset button replaces the current input value outright rather than adding to it, and the active preset gets a highlighted border when its value matches the typed amount exactly.
  • The credit total only appears when creditsPerDollar is passed and the current amount is valid, it's computed inline on every render rather than stored in state.
  • The submit button's label appends the formatted amount only while the amount is valid, so the button always describes what clicking it will actually charge.

Frequently asked questions