13 · Маркетинг

Фильтр и поиск по каталогу в Tilda
готовый код.

Фильтрует карточки Zero Block по категориям и тексту, показывает количество результатов и сохраняет состояние в URL.

Забрать код ↓
Технология
HTML + CSS + JS
Установка
20 минут
Куда вставлять
Zero Block + T123
Обновлено
08.09.2026

Сначала посмотрите,
как это работает.

Live demoФильтр каталога

Найдено: 6

01 · sites

Интернет-магазин

02 · sites

Лендинг продукта

03 · branding

Фирменный стиль

04 · branding

Брендбук

05 · seo

SEO-аудит

06 · seo

Структура сайта

Скопируйте.
Вставьте. Опубликуйте.

Код не требует сборки или установки библиотек. Перед запуском замените значения, отмеченные в инструкции ниже.

Готовый код
<div class="tselno-filter" data-catalog-filter>
  <label>
    <span>Поиск по каталогу</span>
    <input type="search" placeholder="Название или характеристика" data-filter-search>
  </label>
  <div class="tselno-filter__buttons">
    <button type="button" data-filter="all">Все</button>
    <button type="button" data-filter="sites">Сайты</button>
    <button type="button" data-filter="branding">Брендинг</button>
    <button type="button" data-filter="seo">SEO</button>
  </div>
  <p><b data-filter-count>0</b> результатов</p>
  <p class="tselno-filter__empty" data-filter-empty hidden>Ничего не найдено. Измените запрос или категорию.</p>
</div>

<style>
.tselno-filter { --filter-text: #10110f; --filter-accent: #d9ff43; color: var(--filter-text); font-family: Arial, sans-serif; }
.tselno-filter > label { display: grid; gap: 10px; }
.tselno-filter > label span { font-size: 13px; }
.tselno-filter input { min-height: 58px; padding: 0 16px; border: 1px solid var(--filter-text); border-radius: 0; background: transparent; font-size: 16px; }
.tselno-filter__buttons { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 8px; }
.tselno-filter__buttons button { min-height: 44px; padding: 0 16px; border: 1px solid var(--filter-text); background: transparent; color: inherit; cursor: pointer; }
.tselno-filter__buttons button.is-active { background: var(--filter-accent); }
.tselno-filter > p { margin: 18px 0 0; font-size: 13px; }
.tselno-filter__empty { padding: 24px; border: 1px solid var(--filter-text); }
</style>

<script>
(function () {
  var root = document.querySelector('[data-catalog-filter]');
  if (!root) return;
  var cards = Array.from(document.querySelectorAll('.js-catalog-card'));
  var buttons = Array.from(root.querySelectorAll('[data-filter]'));
  var search = root.querySelector('[data-filter-search]');
  var count = root.querySelector('[data-filter-count]');
  var empty = root.querySelector('[data-filter-empty]');
  var params = new URLSearchParams(window.location.search);
  var category = params.get('filter') || 'all';
  search.value = params.get('q') || '';

  function hasCategory(card, value) {
    if (value === 'all') return true;
    return card.classList.contains('js-category-' + value);
  }

  function apply() {
    var query = search.value.trim().toLowerCase();
    var visible = 0;
    cards.forEach(function (card) {
      var matches = hasCategory(card, category) && (!query || card.textContent.toLowerCase().includes(query));
      card.hidden = !matches;
      card.style.display = matches ? '' : 'none';
      if (matches) visible += 1;
    });
    buttons.forEach(function (button) {
      var active = button.dataset.filter === category;
      button.classList.toggle('is-active', active);
      button.setAttribute('aria-pressed', String(active));
    });
    count.textContent = String(visible);
    empty.hidden = visible !== 0;

    var url = new URL(window.location.href);
    category === 'all' ? url.searchParams.delete('filter') : url.searchParams.set('filter', category);
    query ? url.searchParams.set('q', query) : url.searchParams.delete('q');
    history.replaceState(null, '', url.pathname + url.search + url.hash);
  }

  buttons.forEach(function (button) {
    button.addEventListener('click', function () { category = button.dataset.filter; apply(); });
  });
  search.addEventListener('input', apply);
  apply();
})();
</script>

Четыре шага.

  1. 01

    Присвойте каждой карточке Zero Block класс js-catalog-card и один класс категории: js-category-sites, js-category-branding или js-category-seo.

  2. 02

    Добавьте T123 над каталогом, вставьте код и переименуйте кнопки и data-filter под свои категории.

  3. 03

    Если карточки находятся внутри групп, назначайте класс именно внешней группе, которую нужно полностью скрывать.

  4. 04

    Опубликуйте страницу и проверьте фильтры, поиск, пустой результат и открытие ссылки с параметрами filter и q.

Подстройте под себя.

Категории
data-filter у кнопки должен совпадать с окончанием класса js-category-на-карточке.
Поиск
Скрипт ищет по всему видимому тексту карточки без учёта регистра.
Состояние URL
Параметры filter и q позволяют сохранить или отправить выбранную подборку.

Не нашли нужное?
Соберём под ваш сайт.

Опишите задачу и пришлите ссылку на страницу. Посмотрим, можно ли решить её готовым кодом или нужна индивидуальная разработка.

Обсудить в Telegram ↗