Формы
Онлайн-оплата заказа
Блок оплаты для интернет-магазинов, сайтов услуг, клиник и онлайн-записи. Пользователь видит состав заказа, выбирает способ оплаты и получает понятное состояние перед отправкой платежа.
Онлайн-оплата
Оплата без лишних шагов
Пользователь видит заказ, выбирает способ оплаты и получает понятную проверку формы до отправки.
<section class="pay-checkout">
<div class="pay-checkout__head">
<span class="pay-checkout__badge">Онлайн-оплата</span>
<h2>Оплата без лишних шагов</h2>
<p>
Пользователь видит заказ, выбирает способ оплаты и получает понятную проверку формы до отправки.
</p>
</div>
<div class="pay-checkout__grid">
<form class="pay-form">
<div class="pay-form__group">
<h3>Контактные данные</h3>
<label>
Имя
<input class="pay-name" type="text" placeholder="Александр">
</label>
<label>
Email
<input class="pay-email" type="email" placeholder="name@example.com">
</label>
</div>
<div class="pay-form__group">
<h3>Способ оплаты</h3>
<div class="pay-methods">
<button class="pay-method active" type="button" data-method="Банковская карта">
<span>💳</span>
<strong>Карта</strong>
</button>
<button class="pay-method" type="button" data-method="СБП">
<span>⚡</span>
<strong>СБП</strong>
</button>
<button class="pay-method" type="button" data-method="Счёт для юрлица">
<span>📄</span>
<strong>Счёт</strong>
</button>
</div>
</div>
<div class="pay-card-fields">
<label>
Номер карты
<input class="pay-card-number" type="text" inputmode="numeric" maxlength="19" placeholder="0000 0000 0000 0000">
</label>
<div class="pay-card-fields__row">
<label>
Срок
<input class="pay-card-date" type="text" inputmode="numeric" maxlength="5" placeholder="MM/YY">
</label>
<label>
CVC
<input class="pay-card-cvc" type="text" inputmode="numeric" maxlength="3" placeholder="123">
</label>
</div>
</div>
<label class="pay-agree">
<input class="pay-agree-input" type="checkbox">
<span>Согласен с условиями оплаты</span>
</label>
<button class="pay-submit" type="submit">
Перейти к оплате
</button>
<p class="pay-form__message">
Заполните данные — интерфейс покажет готовность к оплате.
</p>
</form>
<aside class="pay-summary">
<span class="pay-summary__eyebrow">Ваш заказ</span>
<div class="pay-summary__item">
<div>
<strong>Консультация специалиста</strong>
<span>1 встреча</span>
</div>
<b>2 500 ₽</b>
</div>
<div class="pay-summary__item">
<div>
<strong>Индивидуальные рекомендации</strong>
<span>после консультации</span>
</div>
<b>900 ₽</b>
</div>
<div class="pay-summary__promo">
<input class="pay-promo" type="text" placeholder="Промокод">
<button class="pay-promo-button" type="button">OK</button>
</div>
<div class="pay-summary__total">
<span>Итого</span>
<strong><span class="pay-total">3 400</span> ₽</strong>
</div>
<div class="pay-summary__status">
<span class="pay-status-dot"></span>
<p class="pay-status-text">Ожидаем заполнения формы</p>
</div>
<div class="pay-summary__method">
Способ оплаты: <strong class="pay-selected-method">Банковская карта</strong>
</div>
</aside>
</div>
</section>
.pay-checkout {
padding: 46px;
border-radius: 28px;
overflow: hidden;
background:
radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.30), transparent 32%),
radial-gradient(circle at 88% 82%, rgba(34, 197, 94, 0.18), transparent 34%),
linear-gradient(135deg, #020617, #0f172a);
}
.pay-checkout__head {
max-width: 860px;
margin-bottom: 34px;
}
.pay-checkout__badge {
display: inline-flex;
margin-bottom: 16px;
padding: 8px 13px;
border-radius: 999px;
color: #bbf7d0;
background: rgba(34, 197, 94, 0.12);
border: 1px solid rgba(34, 197, 94, 0.35);
font-size: 13px;
}
.pay-checkout__head h2 {
margin: 0 0 16px;
color: #ffffff;
font-size: clamp(32px, 5vw, 56px);
line-height: 1.02;
letter-spacing: -0.05em;
}
.pay-checkout__head p {
color: #cbd5e1;
font-size: 17px;
line-height: 1.7;
}
.pay-checkout__grid {
display: grid;
grid-template-columns: 1fr 0.85fr;
gap: 26px;
align-items: start;
}
.pay-form,
.pay-summary {
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 26px;
background: rgba(15, 23, 42, 0.78);
box-shadow: 0 28px 80px rgba(2, 6, 23, 0.5);
}
.pay-form {
display: grid;
gap: 22px;
padding: 26px;
}
.pay-form__group h3 {
margin: 0 0 14px;
color: #ffffff;
font-size: 18px;
}
.pay-form label {
display: grid;
gap: 8px;
margin-bottom: 14px;
color: #dbeafe;
font-size: 14px;
}
.pay-form input,
.pay-summary__promo input {
width: 100%;
border: 1px solid #334155;
border-radius: 16px;
padding: 13px 14px;
color: #ffffff;
background: #020617;
outline: none;
}
.pay-form input:focus,
.pay-summary__promo input:focus {
border-color: #60a5fa;
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.16);
}
.pay-methods {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.pay-method {
border: 1px solid #334155;
border-radius: 18px;
padding: 16px;
color: #cbd5e1;
background: #020617;
cursor: pointer;
transition: 0.25s;
}
.pay-method span,
.pay-method strong {
display: block;
}
.pay-method span {
margin-bottom: 8px;
font-size: 24px;
}
.pay-method.active,
.pay-method:hover {
border-color: #22c55e;
background: rgba(34, 197, 94, 0.12);
transform: translateY(-2px);
}
.pay-card-fields__row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.pay-agree {
display: flex !important;
grid-template-columns: none !important;
align-items: center;
gap: 10px !important;
margin: 0 !important;
}
.pay-agree input {
width: auto;
accent-color: #22c55e;
}
.pay-submit {
border: 0;
border-radius: 16px;
padding: 15px 18px;
color: #ffffff;
background: linear-gradient(135deg, #16a34a, #2563eb);
cursor: pointer;
transition: 0.25s;
}
.pay-submit:hover {
transform: translateY(-2px);
}
.pay-form__message {
margin: 0;
color: #94a3b8;
font-size: 14px;
}
.pay-summary {
position: sticky;
top: 110px;
padding: 28px;
overflow: hidden;
}
.pay-summary::before {
content: "";
position: absolute;
width: 260px;
height: 260px;
right: -110px;
top: -110px;
border-radius: 50%;
background: radial-gradient(circle, rgba(34, 197, 94, 0.25), transparent 70%);
}
.pay-summary > * {
position: relative;
z-index: 2;
}
.pay-summary__eyebrow {
display: inline-flex;
margin-bottom: 18px;
color: #94a3b8;
}
.pay-summary__item {
display: flex;
justify-content: space-between;
gap: 16px;
padding: 16px 0;
border-bottom: 1px solid #334155;
}
.pay-summary__item strong,
.pay-summary__item b {
color: #ffffff;
}
.pay-summary__item span {
display: block;
margin-top: 4px;
color: #94a3b8;
font-size: 13px;
}
.pay-summary__promo {
display: grid;
grid-template-columns: 1fr auto;
gap: 10px;
margin: 22px 0;
}
.pay-promo-button {
border: 1px solid #334155;
border-radius: 16px;
padding: 0 16px;
color: #ffffff;
background: #020617;
cursor: pointer;
}
.pay-summary__total {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin: 24px 0;
color: #cbd5e1;
}
.pay-summary__total strong {
color: #ffffff;
font-size: 38px;
letter-spacing: -0.04em;
}
.pay-summary__status {
display: flex;
align-items: center;
gap: 12px;
border: 1px solid #334155;
border-radius: 18px;
padding: 14px;
background: #020617;
}
.pay-status-dot {
width: 12px;
height: 12px;
flex: 0 0 auto;
border-radius: 50%;
background: #f59e0b;
box-shadow: 0 0 20px rgba(245, 158, 11, 0.6);
}
.pay-status-text {
margin: 0;
color: #cbd5e1;
}
.pay-summary__method {
margin-top: 16px;
color: #94a3b8;
}
.pay-summary__method strong {
color: #dbeafe;
}
.pay-summary.is-ready .pay-status-dot {
background: #22c55e;
box-shadow: 0 0 20px rgba(34, 197, 94, 0.7);
}
.pay-summary.is-error .pay-status-dot {
background: #ef4444;
box-shadow: 0 0 20px rgba(239, 68, 68, 0.7);
}
.pay-summary.is-updated {
animation: payPulse 0.3s ease;
}
@keyframes payPulse {
from {
opacity: 0.76;
transform: scale(0.985);
}
to {
opacity: 1;
transform: scale(1);
}
}
@media (max-width: 900px) {
.pay-checkout {
padding: 26px 18px;
}
.pay-checkout__grid {
grid-template-columns: 1fr;
}
.pay-summary {
position: static;
}
}
@media (max-width: 560px) {
.pay-methods,
.pay-card-fields__row {
grid-template-columns: 1fr;
}
.pay-summary__total {
align-items: flex-start;
flex-direction: column;
}
}
const payMethods = document.querySelectorAll(".pay-method");
const paySelectedMethod = document.querySelector(".pay-selected-method");
const payName = document.querySelector(".pay-name");
const payEmail = document.querySelector(".pay-email");
const payCardNumber = document.querySelector(".pay-card-number");
const payCardDate = document.querySelector(".pay-card-date");
const payCardCvc = document.querySelector(".pay-card-cvc");
const payAgree = document.querySelector(".pay-agree-input");
const payForm = document.querySelector(".pay-form");
const payMessage = document.querySelector(".pay-form__message");
const paySummary = document.querySelector(".pay-summary");
const payStatusText = document.querySelector(".pay-status-text");
const payPromo = document.querySelector(".pay-promo");
const payPromoButton = document.querySelector(".pay-promo-button");
const payTotal = document.querySelector(".pay-total");
let currentTotal = 3400;
let discountApplied = false;
function updatePayStatus() {
const nameReady = payName.value.trim().length >= 2;
const emailReady = payEmail.value.includes("@") && payEmail.value.includes(".");
const cardReady = payCardNumber.value.replace(/\s/g, "").length >= 16 &&
payCardDate.value.length === 5 &&
payCardCvc.value.length === 3;
const ready = nameReady && emailReady && cardReady && payAgree.checked;
paySummary.classList.remove("is-ready", "is-error", "is-updated");
void paySummary.offsetWidth;
paySummary.classList.add("is-updated");
if (ready) {
paySummary.classList.add("is-ready");
payStatusText.textContent = "Готово к оплате";
payMessage.textContent = "Данные выглядят корректно. Можно переходить к оплате.";
payMessage.style.color = "#86efac";
} else {
payStatusText.textContent = "Ожидаем заполнения формы";
payMessage.textContent = "Заполните данные — интерфейс покажет готовность к оплате.";
payMessage.style.color = "#94a3b8";
}
}
function formatCardNumber(value) {
return value.replace(/\D/g, "").slice(0, 16).replace(/(.{4})/g, "$1 ").trim();
}
function formatCardDate(value) {
const clean = value.replace(/\D/g, "").slice(0, 4);
if (clean.length <= 2) {
return clean;
}
return clean.slice(0, 2) + "/" + clean.slice(2);
}
payMethods.forEach(function (method) {
method.addEventListener("click", function () {
payMethods.forEach(item => item.classList.remove("active"));
method.classList.add("active");
paySelectedMethod.textContent = method.dataset.method;
updatePayStatus();
});
});
[payName, payEmail, payAgree].forEach(function (field) {
field.addEventListener("input", updatePayStatus);
field.addEventListener("change", updatePayStatus);
});
payCardNumber.addEventListener("input", function () {
payCardNumber.value = formatCardNumber(payCardNumber.value);
updatePayStatus();
});
payCardDate.addEventListener("input", function () {
payCardDate.value = formatCardDate(payCardDate.value);
updatePayStatus();
});
payCardCvc.addEventListener("input", function () {
payCardCvc.value = payCardCvc.value.replace(/\D/g, "").slice(0, 3);
updatePayStatus();
});
payPromoButton.addEventListener("click", function () {
if (discountApplied) {
return;
}
if (payPromo.value.trim().toLowerCase() === "start") {
currentTotal -= 500;
discountApplied = true;
payTotal.textContent = new Intl.NumberFormat("ru-RU").format(currentTotal);
payPromoButton.textContent = "−500";
payPromoButton.style.color = "#86efac";
}
});
payForm.addEventListener("submit", function (event) {
event.preventDefault();
updatePayStatus();
if (!paySummary.classList.contains("is-ready")) {
paySummary.classList.add("is-error");
payStatusText.textContent = "Проверьте данные";
payMessage.textContent = "Не все поля заполнены корректно.";
payMessage.style.color = "#fca5a5";
}
});
updatePayStatus();