Перейти к содержимому
Забрать бесплатно
Модификации выключены. Так эта страница выглядит на обычной Тильде.

Чекбокс согласия на обработку данных в форме Тильды

28 июля 2026 7 МИН КОМАНДА MODKOD

Галочку «согласен с политикой» в Тильде ставят в редакторе за минуту, и на вид всё работает: без неё форма не отправляется. Но проверка обязательности считает отмеченные поля по имени, а имя у чекбокса по умолчанию одно и то же — Checkbox. Два таких чекбокса в одной форме, и любой из них закрывает требование обоих. В заявке при этом не остаётся ни текста согласия, ни адреса политики. Всё проверено вызовами её собственного валидатора.

✓ ПРОВЕРЕНО 28 июля 2026 обязательность чекбокса при совпадении имён полей, состав заявки от t_serializeArray, реакция на клик по ссылке внутри label, привязка сообщения об ошибке к полю в дереве доступности — разметка чекбокса согласия из снятой страницы modkit/stand/form.html и рантайм форм Тильды в Chromium — вызовами window.tildaForm.validate, showErrors и t_serializeArray

Короткий ответ

Обязательность чекбокса Тильда проверяет по имени поля: [name="…"]:checked во всей форме. Имя по умолчанию у всех чекбоксов одинаковое, поэтому второй чекбокс закрывает требование первого — разведите имена в редакторе. В заявку уезжает только Checkbox: yes: ни текста согласия, ни адреса политики там нет.

Что стоит в разметке

Это дословно из настоящей страницы Тильды, снятой целиком:

<div class="t-input-group t-input-group_cb " data-input-lid="3523145038416"
     data-field-type="cb" data-field-name="Checkbox">
  <div class="t-input-block ">
    <label class="t-checkbox__control t-checkbox__control_flex t-text t-text_xs">
      <input type="checkbox" name="Checkbox" value="yes"
             class="t-checkbox js-tilda-rule" data-tilda-req="1" aria-required="true">
      <div class="t-checkbox__indicator"></div>
      <span>Я согласен с <a href="…/policy" target="_blank"
        rel="noreferrer noopener">политикой по работе с персональными данными</a></span>
    </label>
  </div>
  <div class="t-input-error" aria-live="polite" id="error_3523145038416"></div>
</div>

Сделано аккуратно: настоящий <input type="checkbox">, подпись обёрнута в <label>, у ссылки rel="noreferrer noopener", контейнер ошибки с aria-live="polite". Три вещи из этой разметки решают всё дальнейшее: name="Checkbox", value="yes" и data-tilda-req="1".

Обязательность считается по имени

Вот как проверка решает, отмечен ли обязательный чекбокс:

var d = !!parseInt(u.getAttribute('data-tilda-req') || 0, 10);
var A = 'checkbox' === y || 'radio' === y;
var F = r.querySelectorAll('[name="' + b + '"]:checked').length;
…
if (d && (E || A && !F)) v.type.push('req');

b — это name поля, r — вся форма. То есть требование считается закрытым, если в форме отмечен любой элемент с этим именем.

Замер: два чекбокса в одной форме, оба с разметкой выше, оба name="Checkbox" — первый «согласен с политикой», второй «хочу получать новости». Прогнал её собственный валидатор, window.tildaForm.validate(form):

Что отмеченоОшибокКаких
ничего2Checkbox:req, Checkbox:req
согласие0—
только новости0—

Форма отправляется, согласия нет. Ни ошибки в консоли, ни следа в заявке — по которой это уже не восстановить, см. следующий раздел.

Лечится настройками, кода не нужно: в редакторе у каждого чекбокса задайте своё имя переменной — Consent и News. После этого имена в проверке разные, и каждое требование отвечает за себя.

Что на самом деле уезжает в заявку

Замер тем же сериализатором, которым Тильда собирает заявку. Отмечены оба чекбокса, в текстовом поле имя:

Name = Иван
Checkbox = yes
Checkbox = yes
Что искали в заявкеЕсть
текст рядом с галочкой («согласен с политикой…»)нет
адрес политикинет
различие между согласием и новостяминет — две одинаковые строки
время отметкинет

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

if (!(!r[a].name || r[a].disabled || ['file','reset','submit','button'].indexOf(r[a].type) > -1 || n(r[a])))
  if ('select-multiple' !== r[a].type) {
    if (!(['checkbox','radio'].indexOf(r[a].type) > -1) || r[a].checked) { … e.push({name: i, value: s}) }
  }

Отсюда же второе: неотмеченный чекбокс в заявке не оставляет ничего. Не Checkbox: no, а вообще ничего — условие || r[a].checked отсекает его до push. Если по заявке нужно видеть «на новости не подписался», для этого нужно отдельное поле, а не отсутствие поля.

Что положить в заявку, чтобы через год было понятно, на что человек согласился: адрес политики и её версию. Одно скрытое поле, значение прописано в разметке — кода не нужно вовсе:

<input type="hidden" name="PolicyVersion" value="policy-2026-07-28">

Сериализатору .t-input-group не нужен — достаточно name и отсутствия disabled; это проверено отдельным замером на скрытом поле без группы. Менять версию в этом поле нужно ровно тогда, когда меняется политика: значение в заявке и есть ответ на вопрос, какую редакцию человек видел.

Где про это читать

Юридическую достаточность такой записи оценивает юрист, а не эта статья. Здесь только техника: в заявке есть то, что вы туда положили, и ничего кроме. Но отправить читателя к юристу и на этом закончить — половина ответа, поэтому вот первоисточники, по которым видно, зачем запись в заявке нужна вообще.

Первое: собирая данные через форму на своём сайте, оператором персональных данных становитесь вы, а не Тильда — она обрабатывает их по вашему поручению. Так это описано в её собственной справке, «Обработка персональных данных на сайте»; оттуда же рекомендация про чекбокс со ссылкой на политику под каждой формой и про саму опубликованную политику.

Второе: требования к согласию — в статье 9 152-ФЗ. Часть 1 говорит, каким согласие должно быть — «конкретным, предметным, информированным, сознательным и однозначным» — и что дано оно может быть в любой форме, позволяющей подтвердить факт его получения. Часть 3 говорит, кто подтверждает: обязанность предоставить доказательство получения согласия возлагается на оператора. Рядом стоит часть 1 статьи 15 того же закона — про обработку для продвижения товаров и услуг: она считается идущей без предварительного согласия, пока оператор не докажет обратное.

Техническая часть статьи упирается ровно сюда. Доказывать — вам, а в заявке лежит Checkbox = yes без подписи, без адреса политики и без времени; две галочки с одним именем дают две одинаковые строки, по которым согласие на обработку и подписку на новости не различить. Отсюда и оба совета выше — развести имена полей и положить версию политики скрытым полем: не «чтобы юрист был доволен», а чтобы у записи было содержание.

Смотреть стоит действующий текст по ссылке, а не пересказ, включая этот: часть 1 статьи 9 правилась 266-ФЗ от 14.07.2022 и 156-ФЗ от 24.06.2025.

Клик по ссылке внутри подписи

Обычное опасение: ссылка на политику лежит внутри <label>, значит клик по ней переключит галочку. Замер на её же разметке:

Куда кликнулиГалочка
по ссылке на политикуне переключилась
по тексту рядом со ссылкойпереключилась

Так и должно быть: браузер не передаёт активацию <label> дальше, если клик пришёл по интерактивному элементу внутри неё. Плюс target="_blank" — политика открывается в новой вкладке и не уносит заполненную форму. Здесь у Тильды всё в порядке, править нечего.

Сообщение об ошибке видно, но не полю

Как выглядит ошибка на незакрытом согласии — замер после showErrors:

ЧтоЗначение
текст в .t-input-errorОбязательное поле
класс группы… t-input-group_cb js-error-control-box
aria-invalid на inputне поставлен
aria-describedby на inputне поставлен
id у самого inputнет
поле в дереве доступностиcheckbox «Я согласен с политикой…», invalid=false

Текст ошибки объявится: .t-input-error живёт с aria-live="polite". Но само поле остаётся в дереве доступности корректным, и связи «у этого чекбокса вот эта ошибка» нет ни одной. Кто вернулся к форме через минуту, ошибку услышит уже не здесь и не сейчас.

Это правится своим кодом на tildaform:aftererror — событие всплывает, поэтому слушать удобно на документе:

document.addEventListener('tildaform:aftererror', function (e) {
  e.target.querySelectorAll('.js-error-control-box').forEach(function (group) {
    var input = group.querySelector('input, textarea, select');
    var error = group.querySelector('.t-input-error');
    if (!input || !error) return;
    if (!error.id) error.id = 'err-' + Math.random().toString(36).slice(2);
    input.setAttribute('aria-invalid', 'true');
    input.setAttribute('aria-describedby', error.id);
  });
});

Класс js-error-control-box ставит сама Тильда — это её собственный признак группы с ошибкой, и опираться на него надёжнее, чем искать непустые контейнеры. Снимать aria-invalid нужно на change поля, иначе он останется висеть после исправления.

Своё сообщение вместо «Обязательное поле» тоже ставится без кода: рантайм сначала ищет пользовательский текст (t_forms__getCustomMessage) и только потом берёт свой — в редакторе это поле «Текст ошибки».

Что проверить у себя

// 1. Имена всех чекбоксов формы — совпадений быть не должно
[...document.querySelectorAll('.t-form input[type="checkbox"]')]
  .map(c => c.name + (c.dataset.tildaReq ? ' (обязательный)' : ''));

// 2. Сколько полей закрывают требование каждого имени
new Set([...document.querySelectorAll('.t-form input[type="checkbox"]')].map(c => c.name));

// 3. Что уедет в заявку прямо сейчас
t_serializeArray(document.querySelector('.t-form')).map(f => f.name + '=' + f.value);

// 4. Есть ли в заявке след политики
t_serializeArray(document.querySelector('.t-form')).some(f => /policy|Policy/.test(f.name + f.value));

// 5. Ссылка в подписи открывается в новой вкладке
[...document.querySelectorAll('.t-checkbox__control a')].map(a => a.target + ' ' + a.rel);

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

Свободные моды библиотеки — в каталоге. Если в форме нужны согласия по нескольким основаниям, запись версии политики со временем или связь ошибок с полями по всему сайту сразу — это доработка форм.

Вопросы по этой статье 3

Да, если чекбокс в форме один. Проверка обязательности считает отмеченные поля с этим именем во всей форме, поэтому второй чекбокс с тем же именем — например «хочу получать новости» — закрывает требование за согласие. Имена полей нужно развести в редакторе.