Billing Education Discount Application
An application form for student, teacher, and institution pricing. A role picker recalculates the discount and estimated monthly savings live, a school email field flags addresses that don't look like a .edu domain without blocking submission, and a file upload button collects proof of enrollment. Submitting shows a loading state followed by a confirmation screen. Built for SaaS upgrade and onboarding funnels that offer academic pricing.
Docs
Installation
A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button, input, label dependencies and any missing npm packages, and installs them straight into your project.
npx shadcn add https://staaarter.com/r/billing-education-discount-application.jsonPrefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing52.tsx instead.
Usage
The file also exports billing52Demo, 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 { Billing52, billing52Demo } from "@/components/blocks/billing/billing52"; export default function Page() { return <Billing52 {...billing52Demo} />; }
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| heading | string | "Apply for the education discount" | Form heading. |
| description | string | (see source) | Supporting line under the heading. |
| planPrice | number | none | Standard monthly price in dollars, before any discount. |
| tiers | EducationTier[] | none | Roles the applicant can pick, each with its own discount percentage. |
| defaultRole | "student" | "teacher" | "institution" | tiers[0].role | Which role is selected when the form first renders. |
| submitLabel | string | "Submit application" | Label on the submit button. |
| className | string | none | Extra classes for the outer form container. |
Types
type EducationRole = "student" | "teacher" | "institution"; interface EducationTier { role: EducationRole; label: string; discountPercent: number; }
Behavior notes
- Selecting a role is a real radiogroup of buttons, not a native select, so it recalculates the savings preview immediately and works with keyboard navigation and screen readers.
- The email field doesn't block submission if it's not a .edu address, it just shows an amber note underneath saying additional verification may be needed. Actual verification happens on your backend.
- The file upload button triggers a hidden native file input via a ref and click(), then shows the selected file's name next to the button. No file is actually uploaded anywhere, wire an onChange handler of your own if you need to send it to storage.
- Submitting sets a loading state for about 900ms, then replaces the entire form with a confirmation message. There's no callback prop for the submitted data, so lift state up or handle the POST inside your own onSubmit if you fork the component.
- Estimated savings are computed as planPrice times the selected tier's discountPercent, with the discounted price and original price both shown so the benefit is visible before submitting.
Frequently asked questions
More Billing Blocks
View all →Billing Invoice List
Invoice history table with status badges, formatted amounts, and a per-row download link, built with shadcn/ui and Tailwind CSS.
Billing Failed Payment Alert
High-contrast failed-payment alert with a message, a retry button, and an optional update-payment-method button, built with shadcn/ui and Tailwind CSS.
Billing Credit Balance
Compact credit balance card with a large total, an optional purchased-versus-promotional breakdown, a low-balance notice, and a top-up button.
Billing Payment Methods
A saved payment method list for React and Next.js with brand icons, a default badge, near-expiry warnings, and remove/set-default actions per row.
Billing Add Card
A card entry form for React and Next.js with auto-formatted fields, internal brand detection, and per-field validation feedback built with shadcn/ui and Tailwind CSS.
Billing Coupon Code
An inline promo code input for React and Next.js with a simulated loading state, an applied summary showing the discount amount, and an invalid-code message.