Умный FAQ с поиском
Блок частых вопросов для сайтов услуг, клиник, интернет-магазинов и корпоративных сайтов. Посетитель быстро находит нужный ответ через поиск или фильтр по теме, поэтому меньше теряется и чаще доходит до заявки.
Ответы находятся без прокрутки всей страницы
Пользователь вводит вопрос или выбирает тему, а блок сразу показывает только подходящие ответы.
Да. Такой FAQ можно использовать для клиники, сайта услуг, интернет-магазина, школы, портфолио или корпоративного сайта.
В реальном проекте вопросы можно хранить в базе данных и редактировать через админ-панель без изменения кода.
Поиск срабатывает сразу при вводе. Пользователю не нужно читать длинный список вопросов, если он ищет что-то конкретное.
Он снимает частые сомнения до обращения: про оплату, сроки, запись, доставку, формат услуги и гарантии.
Да. В ответ можно добавить кнопку записи, ссылку на Telegram, форму заявки или переход к нужной услуге.
Попробуйте другой запрос или выберите тему “Все”.
<section class="smart-faq">
<div class="smart-faq__aside">
<span class="smart-faq__badge">FAQ</span>
<h2>Ответы находятся без прокрутки всей страницы</h2>
<p>
Пользователь вводит вопрос или выбирает тему, а блок сразу показывает
только подходящие ответы.
</p>
<div class="smart-faq__search">
<input class="smart-faq__input" type="search" placeholder="Например: оплата, запись, сроки">
<button class="smart-faq__clear" type="button">Очистить</button>
</div>
<div class="smart-faq__topics">
<button class="smart-faq__topic active" type="button" data-topic="all">Все</button>
<button class="smart-faq__topic" type="button" data-topic="service">Услуги</button>
<button class="smart-faq__topic" type="button" data-topic="payment">Оплата</button>
<button class="smart-faq__topic" type="button" data-topic="time">Сроки</button>
</div>
</div>
<div class="smart-faq__content">
<article class="smart-faq__item open" data-topic="service">
<button class="smart-faq__question" type="button">
<span>Можно ли адаптировать блок под мой сайт?</span>
<strong>+</strong>
</button>
<div class="smart-faq__answer">
<p>
Да. Такой FAQ можно использовать для клиники, сайта услуг,
интернет-магазина, школы, портфолио или корпоративного сайта.
</p>
</div>
</article>
<article class="smart-faq__item" data-topic="payment">
<button class="smart-faq__question" type="button">
<span>Можно ли добавить вопросы через админку?</span>
<strong>+</strong>
</button>
<div class="smart-faq__answer">
<p>
В реальном проекте вопросы можно хранить в базе данных и редактировать
через админ-панель без изменения кода.
</p>
</div>
</article>
<article class="smart-faq__item" data-topic="time">
<button class="smart-faq__question" type="button">
<span>Как быстро пользователь найдёт ответ?</span>
<strong>+</strong>
</button>
<div class="smart-faq__answer">
<p>
Поиск срабатывает сразу при вводе. Пользователю не нужно читать
длинный список вопросов, если он ищет что-то конкретное.
</p>
</div>
</article>
<article class="smart-faq__item" data-topic="service">
<button class="smart-faq__question" type="button">
<span>Зачем такой блок заказчику?</span>
<strong>+</strong>
</button>
<div class="smart-faq__answer">
<p>
Он снимает частые сомнения до обращения: про оплату, сроки,
запись, доставку, формат услуги и гарантии.
</p>
</div>
</article>
<article class="smart-faq__item" data-topic="payment">
<button class="smart-faq__question" type="button">
<span>Можно ли добавить кнопку заявки внутри ответа?</span>
<strong>+</strong>
</button>
<div class="smart-faq__answer">
<p>
Да. В ответ можно добавить кнопку записи, ссылку на Telegram,
форму заявки или переход к нужной услуге.
</p>
</div>
</article>
<div class="smart-faq__empty">
<strong>Ничего не найдено</strong>
<p>Попробуйте другой запрос или выберите тему “Все”.</p>
</div>
</div>
</section>
.smart-faq {
display: grid;
grid-template-columns: 0.85fr 1.15fr;
gap: 28px;
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(236, 72, 153, 0.18), transparent 34%),
linear-gradient(135deg, #020617, #0f172a);
}
.smart-faq__aside,
.smart-faq__content {
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);
}
.smart-faq__aside {
padding: 28px;
}
.smart-faq__badge {
display: inline-flex;
margin-bottom: 16px;
padding: 8px 13px;
border-radius: 999px;
color: #bfdbfe;
background: rgba(59, 130, 246, 0.16);
border: 1px solid rgba(96, 165, 250, 0.45);
font-size: 13px;
}
.smart-faq h2 {
margin: 0 0 16px;
color: #ffffff;
font-size: clamp(30px, 5vw, 52px);
line-height: 1.03;
letter-spacing: -0.05em;
}
.smart-faq__aside p {
color: #cbd5e1;
line-height: 1.7;
}
.smart-faq__search {
display: flex;
gap: 10px;
margin: 24px 0 18px;
}
.smart-faq__input {
min-width: 0;
flex: 1;
border: 1px solid #334155;
border-radius: 16px;
padding: 13px 14px;
color: #ffffff;
background: #020617;
outline: none;
}
.smart-faq__input:focus {
border-color: #60a5fa;
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.16);
}
.smart-faq__clear {
border: 1px solid #334155;
border-radius: 16px;
padding: 0 14px;
color: #cbd5e1;
background: #0f172a;
cursor: pointer;
}
.smart-faq__topics {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.smart-faq__topic {
border: 1px solid #334155;
border-radius: 999px;
padding: 9px 13px;
color: #cbd5e1;
background: #020617;
cursor: pointer;
transition: 0.25s;
}
.smart-faq__topic:hover,
.smart-faq__topic.active {
color: #ffffff;
border-color: #3b82f6;
background: rgba(59, 130, 246, 0.22);
transform: translateY(-2px);
}
.smart-faq__content {
padding: 18px;
}
.smart-faq__item {
border: 1px solid #334155;
border-radius: 20px;
background: rgba(2, 6, 23, 0.58);
overflow: hidden;
transition: 0.25s;
}
.smart-faq__item + .smart-faq__item {
margin-top: 12px;
}
.smart-faq__item:hover,
.smart-faq__item.open {
border-color: #3b82f6;
}
.smart-faq__question {
width: 100%;
display: flex;
justify-content: space-between;
gap: 18px;
align-items: center;
border: 0;
padding: 18px;
color: #ffffff;
text-align: left;
background: transparent;
cursor: pointer;
}
.smart-faq__question span {
font-size: 17px;
font-weight: 700;
}
.smart-faq__question strong {
width: 30px;
height: 30px;
flex: 0 0 auto;
display: grid;
place-items: center;
border: 1px solid #334155;
border-radius: 50%;
color: #bfdbfe;
transition: 0.25s;
}
.smart-faq__item.open .smart-faq__question strong {
transform: rotate(45deg);
border-color: #3b82f6;
background: rgba(59, 130, 246, 0.18);
}
.smart-faq__answer {
max-height: 0;
overflow: hidden;
transition: max-height 0.28s ease;
}
.smart-faq__item.open .smart-faq__answer {
max-height: 220px;
}
.smart-faq__answer p {
margin: 0;
padding: 0 18px 18px;
color: #cbd5e1;
line-height: 1.7;
}
.smart-faq mark {
color: #ffffff;
background: rgba(59, 130, 246, 0.45);
border-radius: 6px;
padding: 0 3px;
}
.smart-faq__item.is-hidden {
display: none;
}
.smart-faq__empty {
display: none;
border: 1px dashed #334155;
border-radius: 20px;
padding: 28px;
text-align: center;
color: #cbd5e1;
}
.smart-faq__empty strong {
display: block;
margin-bottom: 8px;
color: #ffffff;
font-size: 22px;
}
.smart-faq__empty.is-visible {
display: block;
}
@media (max-width: 850px) {
.smart-faq {
grid-template-columns: 1fr;
padding: 26px 18px;
}
.smart-faq__search {
flex-direction: column;
}
.smart-faq__clear {
min-height: 44px;
}
}
const faqInput = document.querySelector(".smart-faq__input");
const faqClear = document.querySelector(".smart-faq__clear");
const faqTopics = document.querySelectorAll(".smart-faq__topic");
const faqItems = document.querySelectorAll(".smart-faq__item");
const faqEmpty = document.querySelector(".smart-faq__empty");
let activeTopic = "all";
function normalizeText(value) {
return value.toLowerCase().trim();
}
function highlightText(element, query) {
const original = element.dataset.original || element.textContent;
element.dataset.original = original;
if (!query) {
element.innerHTML = original;
return;
}
const safeQuery = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const regex = new RegExp("(" + safeQuery + ")", "gi");
element.innerHTML = original.replace(regex, "<mark>$1</mark>");
}
function filterFaq() {
const query = normalizeText(faqInput.value);
let visibleCount = 0;
faqItems.forEach(function (item) {
const question = item.querySelector(".smart-faq__question span");
const answer = item.querySelector(".smart-faq__answer p");
const text = normalizeText(question.dataset.original || question.textContent) + " " +
normalizeText(answer.textContent);
const topicMatches = activeTopic === "all" || item.dataset.topic === activeTopic;
const searchMatches = !query || text.includes(query);
if (topicMatches && searchMatches) {
item.classList.remove("is-hidden");
visibleCount += 1;
highlightText(question, query);
} else {
item.classList.add("is-hidden");
highlightText(question, "");
}
});
faqEmpty.classList.toggle("is-visible", visibleCount === 0);
}
faqItems.forEach(function (item) {
const button = item.querySelector(".smart-faq__question");
button.addEventListener("click", function () {
item.classList.toggle("open");
});
});
faqTopics.forEach(function (topic) {
topic.addEventListener("click", function () {
faqTopics.forEach(item => item.classList.remove("active"));
topic.classList.add("active");
activeTopic = topic.dataset.topic;
filterFaq();
});
});
faqInput.addEventListener("input", filterFaq);
faqClear.addEventListener("click", function () {
faqInput.value = "";
activeTopic = "all";
faqTopics.forEach(item => item.classList.remove("active"));
document.querySelector('[data-topic="all"]').classList.add("active");
filterFaq();
faqInput.focus();
});
filterFaq();