webdevpuneet.com

NFT Mint Progress — Free Live Minting Card UI

NFT Mint Progress · Cards · Plain HTML, CSS & JS · Live preview

CategoryCards

Copy & paste

Source Code

<div class="nmp-card">
  <div class="nmp-art" aria-hidden="true">
    <div class="nmp-art-glow"></div>
    <span class="nmp-art-emoji">◆</span>
  </div>

  <div class="nmp-head">
    <h3>Genesis Drop</h3>
    <span class="nmp-status" id="nmpStatus">Live</span>
  </div>

  <div class="nmp-progress-row">
    <span class="nmp-minted"><b id="nmpMinted">3417</b> / 5000 minted</span>
    <span class="nmp-pct" id="nmpPct">68%</span>
  </div>
  <div class="nmp-bar" aria-hidden="true"><div class="nmp-bar-fill" id="nmpBarFill" style="width:68.34%"></div></div>

  <div class="nmp-controls">
    <div class="nmp-qty" id="nmpQty">
      <button type="button" class="nmp-qty-btn" id="nmpMinus" aria-label="Decrease quantity">&minus;</button>
      <span class="nmp-qty-val" id="nmpQtyVal">1</span>
      <button type="button" class="nmp-qty-btn" id="nmpPlus" aria-label="Increase quantity">+</button>
    </div>
    <button type="button" class="nmp-mint-btn" id="nmpMintBtn">
      <span class="nmp-spinner" id="nmpSpinner" hidden aria-hidden="true"></span>
      <span id="nmpMintLabel">Mint now &middot; 0.08 ETH</span>
    </button>
  </div>

  <p class="nmp-note" id="nmpNote">Price per NFT: 0.08 ETH + gas</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Single source of truth
mintedCount alone drives the bar fill, percentage text, and sold-out state.
Supply-aware stepper
The plus button disables at both a per-transaction cap and remaining supply.
Loading-then-success flow
A spinner state precedes a genuine confirmation before supply updates.
Sold-out handling
The card automatically disables minting and relabels itself at full supply.
Pulsing live badge
A CSS-only animated dot signals an actively minting drop.
Animated art glow
A drifting radial gradient behind the placeholder artwork adds depth.
Tabular numerals
Minted count and percentage use monospaced digits to avoid layout shift.
Framework-portable state
mintedCount, qty, and minting are plain variables, easy to lift into component state.

About this UI Snippet

NFT Mint Progress — Supply Bar, Quantity Stepper & Mint Confirmation

Screenshot of the NFT Mint Progress snippet rendered live

Every NFT mint page needs the same core widget: how much of the collection is gone, how many you're about to mint, and clear feedback that your transaction went through. This snippet builds that mint progress card — a live "minted / total supply" bar, a bounded quantity stepper, and a mint button that walks through a loading spinner into a genuine success confirmation — with no dependency beyond vanilla JS.

Supply progress driven by one number

mintedCount is the single source of truth. renderProgress() derives the displayed count, the percentage, and the bar's fill width all from it, so there's no way for the bar to show 68% while the text says something else. When mintedCount reaches TOTAL_SUPPLY, the same function flips the whole card into a sold-out state — disabling the mint button and swapping its label — rather than requiring a separate sold-out check elsewhere.

A quantity stepper that respects remaining supply

The +/− stepper is bounded not just by a fixed max (10 per transaction, a common anti-bot limit) but by mintedCount + qty > TOTAL_SUPPLY — so a user can never spin the quantity up to mint more NFTs than actually remain. The plus button disables the instant either limit is hit, giving immediate visual feedback instead of letting the user attempt an invalid mint.

Loading, then a genuine success state

Clicking "Mint now" swaps the button's content for a spinning loader and disables it immediately, simulating the wait for a transaction to confirm. Only after that delay does mintedCount actually increase and the progress bar update — mirroring the real sequence where supply shouldn't visually decrement until the mint transaction is confirmed, not just submitted. The success state then holds briefly with a checkmark and the exact quantity minted before resetting.

A pulsing "Live" status badge

A small pulsing dot next to the "Live" badge (built purely in CSS with an opacity keyframe) signals the drop is actively minting, independent of any specific mint action — the same pattern used for a live visitor counter, reused here to communicate an active drop rather than a static listing.

Extending it for a real drop

Swap the simulated setTimeout delay for an actual contract call (e.g. via ethers.js or viem), and read the real minted count from an on-chain totalSupply() view or an indexer instead of the local variable. Pair this card with a wallet connect button to gate minting until a wallet is connected, and a gas fee estimator to show the total cost including network fees.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA mint card renders showing 3417 of 5000 minted with a 68% progress bar.
  2. 2
    Adjust the quantityUse the +/- stepper — it's capped at 10 per mint and by remaining supply.
  3. 3
    Click "Mint now"The button shows a spinner, then a success checkmark with the minted quantity, then resets.
  4. 4
    Watch the supply updateAfter a successful mint, the progress bar and minted count advance by the minted quantity.
  5. 5
    Reach sold outOnce minted count hits total supply, the button disables and the status badge reads "Sold out".
  6. 6
    Connect a real contractReplace the setTimeout delay with an actual mint transaction and read supply from an on-chain call.

Real-world uses

Common Use Cases

NFT drop pages
Provide the main mint widget for a collection launch, with minted count alone driving the supply bar, percentage text and remaining figure.
Gas-aware checkouts
Show total cost including network fees beside a gas fee estimator, with the plus button disabled at both the per-transaction cap and remaining supply.
Allowlist mints
Adapt the status badge to show allowlist phases, with a wallet connect button gating access to the mint.
Limited product drops
Reuse the supply bar for limited physical or digital product releases, relabelling the card automatically when it sells out.
Creator dashboards and listings
Display live mint progress to a creator, comparing with a donut progress chart, or show minting status on marketplace listings.

Got questions?

Frequently Asked Questions

Both are derived from the single mintedCount variable inside renderProgress() — the percentage, the bar's width, and the displayed count text are all computed from it in one function call, so there is no path where the bar shows a different percentage than the text implies.

The mint button disables and shows a spinner the instant it's clicked, but mintedCount is only incremented inside the setTimeout callback that follows — modeling the real-world gap between submitting a mint transaction and it actually confirming on-chain. Updating supply immediately on click would misrepresent an unconfirmed transaction as a completed mint.

The plus button's click handler and its disabled state both check mintedCount + qty against TOTAL_SUPPLY in addition to a fixed per-transaction cap (10 here, a common anti-bot limit). Once either limit is reached, the button disables so the user cannot spin the quantity past what remains.

Replace the setTimeout delay in the mint handler with an actual contract call (via ethers.js, viem, or your wallet SDK's mint function), and only advance mintedCount and show the success state after the transaction receipt confirms. Read the real minted count from the contract's totalSupply() view function or an indexer on page load and periodically, instead of the hardcoded local variable.

Hold mintedCount, qty, and minting in component state. Derive the bar width, percentage, and disabled states in render from mintedCount and qty exactly as renderProgress()/renderQty() do. Make the mint handler an async function that awaits your real transaction before updating state, showing the spinner while the await is pending.