Create Credit Card Form with Real-Time Preview using JS

Want a modern credit‑card preview UI that updates in real time as users type? In this tutorial you’ll build an interactive credit card form with real-time preview, complete with live number formatting, name and date validation, animated card flip for CVV and a sleek glass‑dark design—using just HTML, CSS and vanilla JavaScript. This component is perfect for checkout pages, payment gateways and responsive finance dashboards.

HTML Structure

Our markup places a 3‑D .card inside a .preview panel beside a structured <form>. Each form <input>—card number, holder, validity, CVV—maps to a matching element on the card. This semantic, keyword‑rich skeleton lays the groundwork for our credit card preview UI.

<div class="main-container flex-c">
        <div class="content-box flex-c">
            <div class="preview">
                <div class="card">
                    <div class="front">
                        <div class="title">CREDIT CARD</div>
                        <div id="chip" class="flex-c">
                            <span></span><span></span><span></span><span></span><span></span>
                        </div>
                        <div class="card-number">0000 0000 0000 0000</div>
                        <div class="card-name">Name Surname</div>
                        <div class="validity-box flex-c">
                            <span>VALID THRU</span>
                            <div class="card-validity">00/00</div>
                        </div>
                        <div class="logo flex-c">MasterCard</div>
                    </div>

                    <div class="back">
                        <div class="top-text">Lorem ipsum dolor sit amet consectetur adipisicing elit.</div>
                        <div class="strip"></div>
                        <div class="box flex-c">
                            <div class="signature"></div>
                            <div class="card-cvv">000</div>
                        </div>
                        <div class="text">
                            <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Aliquid perferendis illum vero,
                                porro totam iure cupiditate ipsum placeat nihil, quibusdam architecto beatae atque ipsam
                                corrupti laudantium? Vel cupiditate laborum id, perspiciatis cumque, eaque inventore
                                molestiae eos a, officia maxime nihil mollitia aut hic quia provident!</p>
                            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Error quod accusamus delectus
                                eius rerum cum officiis quisquam impedit placeat temporibus!</p>
                        </div>
                    </div>
                </div>
            </div>
            <div class="form-container">
                <form>
                    <div class="field">
                        <label for="number">Card Number</label>
                        <input type="text" id="number" oninput="UpdateAccountNumber(this);" maxlength="19">
                    </div>
    
                    <div class="field">
                        <label for="name">Card Holder</label>
                        <input type="text" id="name" oninput="updateCardHolder(this);" maxlength="25">
                    </div>
                    <section>
                        <div class="field">
                            <label for="validity">Valid upto (MM/YY)</label>
                            <input type="text" id="validity" oninput="updateValidity(this)" maxlength="5">
                        </div>
                        <div class="field">
                            <label for="cvv">CVV</label>
                            <input type="text" id="cvv" oninput="updateCardCvv(this)" maxlength="3">
                        </div>
                    </section>
                </form>
            </div>
        </div>
</div>
  • .content-box couples the credit card preview and the payment form side‑by‑side.
  • Each <input> has an id that matches a .card-* element, enabling JavaScript to update text instantly.
  • The card’s .front shows chip, number, name, date and brand logo; .back holds magnetic strip, signature pad and CVV.
  • The preview sits in a perspective wrapper to allow a 3‑D card flip animation on CVV focus.

With structural HTML complete, the preview and form elements are paired, ready for CSS styling and live JavaScript binding—delivering a responsive credit card form with real-time preview that feels professional and intuitive.

Styling with CSS

Styling turns static markup into an animated credit card mock‑up. We rely on CSS variables, 3‑D transforms, gradients and subtle shadows to create depth while keeping a lightweight, mobile‑friendly footprint.

:root {
    --card-height: 180px;
}

.flex-c {
    display: flex;
    justify-content: center;
    align-items: center;
}

.main-container {
    min-height: 100vh;
    min-width: 450px;
}

.content-box {
    position: relative;
    color: #ffffff;
    height: 605px;
    font-family: 'Calibri';
    align-items: flex-end;
}

.preview {
    perspective: 1000px;
    position: absolute;
    top: 15px;
}

.card {
    width: 350px;
    height: var(--card-height);
    transition: transform 1s;
    transform-style: preserve-3d;
    border-radius: 8px;
}

.flipped,
.preview:hover .card {
    transform: rotateY(-180deg);
}

.front,
.back {
    width: 100%;
    height: 100%;
    position: absolute;
    background: #2c2c2c;
    backface-visibility: hidden;
    border-radius: 8px;
    overflow: hidden;
    color: white;
}

.front::after,
.back::after,
.front::before,
.back::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    opacity: 0.5;
}

.front::after {
    background: #1a1a1a;
    border-radius: 0% 0% 0 160px;
    transform: translate(50%, -30%);
    top: 0;
}

.front::before {
    background: #3d3d3d;
    border-radius: 0 160px 0 0;
    transform: translate(-50%, 50%);
}

.title {
    position: absolute;
    right: 0;
    z-index: 1;
    letter-spacing: 1.5px;
    padding: 1rem;
}

#chip {
    top: 10%;
    position: absolute;
    background: #e0ab89;
    width: 15%;
    height: 18%;
    border-radius: 5px;
    margin-left: 15px;
}

#chip span {
    position: absolute;
    background: #e0ab89;
    border: 1px solid black;
}

#chip span:nth-child(1) {
    height: 100%;
    width: 40%;
    border-top: none;
    border-bottom: none;
}

#chip span:nth-child(2) {
    height: 60%;
    width: 40%;
    left: 0;
    border-left: none;
    border-radius: 0 5px 5px 0;
}

#chip span:nth-child(3) {
    height: 60%;
    width: 40%;
    border-right: none;
    border-radius: 5px 0 0 5px;
    right: 0;
}

#chip span:nth-child(4) {
    width: 100%;
    border: none;
    border-bottom: 1px solid black;
}

#chip span:nth-child(5) {
    aspect-ratio: 1/1;
    width: 25%;
    border-radius: 2px;
}

.card-number,
.card-name,
.validity-box {
    position: absolute;
    margin-left: 15px;
}

.card-number {
    top: 42%;
    letter-spacing: 2px;
    font-size: 18px;
    z-index: 1;
}

.card-name {
    bottom: 8%;
    font-size: 14px;
    letter-spacing: 2px;
}

.validity-box {
    left: 40%;
    bottom: 25%;
    width: max-content;
    font-size: 16px;
    z-index: 1;
    letter-spacing: 2px;
}

.validity-box span{
    font-size: 6px;
    letter-spacing: 2px;
    color: #ffffffba;
    width: min-content;
}

.validity-box span::after{
    margin: 0 2px;
    content: '►';
}

.logo {
    position: absolute;
    font-size: 8px;
    width: 20%;
    height: 20%;
    font-weight: bold;
    letter-spacing: 1px;
    bottom: 4%;
    right: 0%;
}

.logo::before,
.logo::after {
    content: '';
    position: absolute;
    width: 50%;
    aspect-ratio: 1/1;
    border-radius: 50%;
}

.logo::before {
    background: rgba(255, 0, 0, 0.525);
    left: 10%
}

.logo::after {
    background: rgba(255, 213, 0, 0.584);
    right: 10%;
}

.back {
    transform: rotateY(-180deg);
    z-index:1;
}

.top-text {
    font-size: 5px;
    padding: 5px 0 1px 5px;
    color: #ffffff99;
}

.strip {
    width: 100%;
    height: 20%;
    background: black;
    position: relative;
    z-index: 1;
}

.box {
    width: 90%;
    height: 20%;
    position: relative;
    background: white;
    margin: 10px auto;
    border-radius: 2px;
    overflow: hidden;
    z-index: 1;
}

.signature {
    width: 85%;
    height: 100%;
    background: repeating-linear-gradient(300deg, #e7e7e7 -2px, #e7e7e7 3px, #cccccc 0px, #cccccc 8px);
}

.card-cvv {
    width: 15%;
    color: black;
    letter-spacing: 2px;
    text-align: center;
}

.text {
    font-size: 6px;
    z-index: 1;
    position: relative;
    display: flex;
    flex-direction: column;
    grid-gap: 10px;
    color: #ffffff99;
    padding: 10px;
}

.form-container {
    width: 400px;
    height: 500px;
    border: 1px solid #1e1e1e;
    padding: 20px;
    background: linear-gradient(45deg, #000000, #0a121f);
    border-radius: 10px;
}

form {
    display: flex;
    flex-direction: column;
    width: 100%;
    transform: translateY(calc(var(--card-height) / 2 + 15px));
    gap: 30px;
}

form section {
    display: flex;
    gap: 10px;
    justify-content: space-between;
}

.field {
    display: flex;
    flex-direction: column;
    margin-bottom: 20px;
    font-size: 12px;
}

input {
    font-size: 16px;
    width: 100%;
    border: none;
    border-bottom: 1px solid #ffffff42;
    padding: 10px 0 4px;
    background: transparent;
    color: #ffffffb8;
    caret-color: white;
}

input:focus {
    outline: none;
}
  • perspective:1000px on .preview and transform-style:preserve-3d on .card enable the X‑axis card flip.
  • Pseudo‑elements (::before & ::after) draw color wedges for a metallic card finish.
  • Absolute positioning aligns .card-number, .card-name, .card-validity and .logo precisely.
  • The form is vertically offset so inputs align visually beneath the preview, keeping the credit card input form neat on any screen.
  • Color accents (chip gold, MasterCard circles) boost realism without extra images.

The CSS delivers a polished, modern credit card UI design: shadows, gradients and transitions combine to mimic plastic depth and physical card behavior—all while remaining pure CSS, no heavy assets, ensuring fast load times.

Implementing JavaScript

A small script links every keystroke to the on‑screen card, formats numbers, validates dates and flips the card when the CVV field is active—transforming static styling into a live credit card preview.

const card = document.querySelector('.card')
const cardNumber = document.querySelector('.card-number')
const cardHolder = document.querySelector('.card-name')
const cardValidity = document.querySelector('.card-validity')
const cardCvv = document.querySelector('.card-cvv')
const inputElement = document.querySelectorAll('input')
const cvvInput = document.querySelector('#cvv');

const dummy = {
    number: '0000 0000 0000 0000',
    name: 'Name Surname',
    validity: '00/00',
    cvv: '000'
}

inputElement.forEach((elem) => {
    elem.addEventListener('input', () => {
        if (elem.value.trim() === '') {
            const key = elem.getAttribute('id');
            const className = 'card-' + key;
            document.querySelector(`.${className}`).innerText = dummy[key]
        }
    })
})

function UpdateAccountNumber(input) {

    let inputValue = input.value.replace(/\D/g, '');
    let formattedValue = '';
    for (let i = 0; i < inputValue.length; i++) {
        if (i > 0 && i % 4 === 0) {
            formattedValue += '\u00A0';
        }
        formattedValue += inputValue[i];
    }
    input.value = formattedValue;
    cardNumber.innerText = formattedValue
}

function updateCardHolder(input) {
    let inputValue = input.value.replace(/[^A-Z a-z]/g, '');
    input.value = inputValue;
    cardHolder.innerText = inputValue
}

function updateValidity(input) {
    let inputValue = input.value.replace(/\D/g, '');
    let formattedValue = '';

    for (let i = 0; i < inputValue.length; i++) {
        const digit = parseInt(inputValue[i]);

        if ((i === 0 && digit > 1) || (i === 1 && digit > 2 && parseInt(inputValue[0]) != 0)) {
            break;
        }
        else if (i === 2) {
            formattedValue += '/';
        }
        formattedValue += digit;
    }
    input.value = formattedValue;
    cardValidity.innerText = formattedValue
}

function updateCardCvv(input) {
    let inputValue = input.value.replace(/\D/g, '');
    input.value = inputValue;
    cardCvv.innerText = inputValue
}

cvvInput.addEventListener('focus', () => card.classList.add('flipped'))
cvvInput.addEventListener('blur', () => card.classList.remove('flipped'))
  • UpdateAccountNumber strips non‑digits, inserts spaces every four chars, writes live to .card-number.
  • updateCardHolder forces alphabetic caps, populating .card-name.
  • updateValidity ensures the month is 01‑12, auto‑slashes to MM/YY, then updates .card-validity.
  • updateCardCvv limits CVV to three digits and mirrors to .card-cvv.
  • When the CVV field gains focus, the card’s .flipped class triggers a Y‑axis rotation so users see the backside—an intuitive cue in any interactive credit card form.
  • On blur, the flip reverses, restoring the front.

With few lines of vanilla JavaScript, we achieve real‑time syncing, basic validation and a tactile flipping animation, elevating the user experience in checkout flows or secure payment modals.

You now have a fully‑functional responsive credit card form with real-time preview that:

  • Updates number, name, expiry and CVV live
  • Auto‑formats inputs and prevents invalid characters
  • Flips the card for CVV entry, boosting usability
  • Combines sleek CSS visuals with lightweight vanilla JS

Plug this animated credit card input form into your next ecommerce site, SaaS billing page or fintech dashboard to give users a polished, high‑trust payment interface.

Leave a Comment

Scroll to Top