lobsite! Войти Регистрация

Документация /

Формы

Любая HTML-форма на сайте в Lobsite может собирать сообщения: направьте её action на /_lobsite/forms/<name> и задеплойте. Не нужно писать бэкенд, подключать скрипт и вставлять ключ. Заявки приходят на страницу «Заявки» в панели и на почту.

<form action="/_lobsite/forms/contact" method="POST">
  <input name="email" type="email" required>
  <textarea name="message" required></textarea>
  <button>Send</button>
</form>

Как работают формы

  • Action задаёт имя формы. /_lobsite/forms/contact — это форма contact. Имена состоят из строчных букв, цифр, - и _. Используйте одно имя на одну задачу (contact, newsletter, quote); несколько страниц могут делить одну форму.
  • Формы находятся при деплое. Деплой читает HTML-файлы и регистрирует каждую форму, которая отправляет данные на /_lobsite/forms/. Форма должна быть в HTML-файле в деплоемой папке: форма, которая появляется только после отрисовки JavaScript, не будет найдена (см. Фреймворки).
  • Поля сохраняются под вашими именами. Каждое поле с name сохраняется как текст. Поле с именем email используется как Reply-To в письме-уведомлении и как заголовок на странице «Заявки». Загрузка файлов не поддерживается.
  • Защита от спама добавляется за вас. Когда страница отдаётся, в форму добавляются скрытое поле-ловушка и подписанная метка времени. Заявки, заполнившие ловушку или пришедшие в течение 2 секунд, откладываются как спам, а слишком частые заявки от одного посетителя отклоняются.
  • После отправки посетитель видит страницу благодарности со ссылкой назад или страницу, заданную в redirect.
  • Формы работают на рабочих URL. Деплои предпросмотра не принимают заявки, а сайт, задеплоенный без аккаунта, начинает принимать их после того, как его заберут.

Типы форм

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

Lobsite выбирает тип при деплое:

  • Форма, в которую посетители вводят email и максимум имя, — это лист ожидания. Скрытые поля, поля, начинающиеся с _, и флажки (согласие) не учитываются.
  • Им же считается форма с именем waitlist, newsletter, signup, subscribe, early-access, beta или notify, какие бы поля в ней ни были.
  • Любая другая форма — форма обратной связи.

Чтобы выбрать самому, задайте type в lobsite.toml:

[forms.launch]
type = "waitlist"   # or "contact"

Записи в листы ожидания хранятся, пока существует форма; остальные заявки — в течение срока хранения по тарифу (см. Ограничения).

Форма обратной связи

Полная страница с именем, email и сообщением. Подписи и значения autocomplete упрощают заполнение; атрибуты required не дают отправить пустую заявку.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Contact</title>
</head>
<body>
  <h1>Get in touch</h1>
  <form action="/_lobsite/forms/contact" method="POST">
    <label>Name
      <input name="name" autocomplete="name" required>
    </label>
    <label>Email
      <input name="email" type="email" autocomplete="email" required>
    </label>
    <label>Message
      <textarea name="message" rows="5" required></textarea>
    </label>
    <button type="submit">Send</button>
  </form>
</body>
</html>

Чтобы проверять те же поля на сервере и отправлять посетителей на свою страницу благодарности, добавьте форму в lobsite.toml и создайте thanks.html:

[forms.contact]
required = ["name", "email", "message"]
types    = { email = "email" }
redirect = "/thanks"

Лист ожидания

До запуска достаточно поля для email. Имя формы делает её листом ожидания; type прямо это указывает. Записи подсчитываются на странице «Заявки» и хранятся, пока существует форма.

<form action="/_lobsite/forms/waitlist" method="POST">
  <label for="wl-email">Get early access</label>
  <input id="wl-email" name="email" type="email" autocomplete="email" placeholder="you@example.com" required>
  <button>Join the waitlist</button>
</form>
[forms.waitlist]
type     = "waitlist"
required = ["email"]
types    = { email = "email" }

Подписка на рассылку

Одного поля достаточно. Вторая форма на том же сайте получает своё имя, поэтому подписки и сообщения разделены на странице «Заявки» и в выгрузках. Форма только с полем email (и максимум именем) — это лист ожидания: см. Типы форм.

<form action="/_lobsite/forms/newsletter" method="POST">
  <label for="nl-email">Get updates by email</label>
  <input id="nl-email" name="email" type="email" autocomplete="email" required>
  <input type="hidden" name="_redirect" value="/subscribed">
  <button>Subscribe</button>
</form>

_redirect — скрытое поле, которое выбирает страницу после отправки. Это должен быть путь или URL на том же сайте; redirect в lobsite.toml имеет приоритет.

Запрос расчёта стоимости

Выпадающие списки, переключатели и флажки работают как обычно. Флажки с одинаковым именем сохраняются как одно значение через запятую.

<form action="/_lobsite/forms/quote" method="POST">
  <input name="name" autocomplete="name" required>
  <input name="email" type="email" autocomplete="email" required>
  <input name="phone" type="tel" autocomplete="tel">
  <select name="budget">
    <option>Under $1,000</option>
    <option>$1,000 to $5,000</option>
    <option>Over $5,000</option>
  </select>
  <fieldset>
    <legend>Services</legend>
    <label><input type="checkbox" name="services" value="Design"> Design</label>
    <label><input type="checkbox" name="services" value="Development"> Development</label>
    <label><input type="checkbox" name="services" value="Hosting"> Hosting</label>
  </fieldset>
  <textarea name="details" required></textarea>
  <button>Request a quote</button>
</form>

Отправка без ухода со страницы

Чтобы показать сообщение на месте, а не загружать новую страницу, отправьте форму через fetch. Соберите тело через new FormData(form), чтобы скрытые антиспам-поля ушли вместе с ним, и запросите JSON заголовком Accept:

<form id="contact" action="/_lobsite/forms/contact" method="POST">
  <input name="email" type="email" required>
  <textarea name="message" required></textarea>
  <button>Send</button>
  <p id="contact-status" role="status"></p>
</form>
<script>
  const form = document.getElementById("contact");
  const status = document.getElementById("contact-status");
  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    status.textContent = "Sending…";
    const res = await fetch(form.action, {
      method: "POST",
      body: new FormData(form),
      headers: { Accept: "application/json" },
    });
    const answer = await res.json();
    if (answer.ok) {
      form.reset();
      status.textContent = "Thanks! We'll be in touch.";
    } else {
      status.textContent = answer.errors ? Object.entries(answer.errors).map(([field, why]) => `${field}: ${why}`).join(", ") : "Something went wrong. Please try again.";
    }
  });
</script>

Ответ — {"ok": true}, или {"ok": false, "errors": {"email": "Required"}} для полей, не прошедших проверку, или {"ok": false, "error": "rate_limited"} (а также too_large, not_found, forms_off). Без скрипта та же форма продолжает работать как обычная.

Фреймворки

React, Vue, Svelte, Astro и остальные работают, если форма есть в собранном HTML — его дают пререндеринг и статический экспорт (Astro и Eleventy по умолчанию, Next.js с output: "export", SvelteKit с prerender, Nuxt с nuxt generate). Оставляйте атрибуты action и method на самом элементе <form>.

В одностраничном приложении форма должна быть в собранном HTML и оставаться в том виде, в каком пришла: форма, существующая только в JavaScript, не регистрируется, и её заявки отклоняются, а форма, которую браузер перерисовал, теряет антиспам-поля, поэтому её сообщения попадают в спам.

// React: a plain form element, prerendered into the HTML.
export function Contact() {
  return (
    <form action="/_lobsite/forms/contact" method="POST">
      <input name="email" type="email" required />
      <textarea name="message" required />
      <button>Send</button>
    </form>
  );
}

Настройки

У каждой формы может быть раздел в lobsite.toml. Все ключи необязательны; настройки едут вместе с деплоем.

[forms.contact]
type      = "contact"                            # contact or waitlist; inferred when left out
required  = ["email", "message"]                 # fields that can't be empty
types     = { email = "email", phone = "tel" }   # text, email, number, url or tel
redirect  = "/thanks"                            # the page shown after sending
notify    = ["you@example.com"]                  # who gets an email for each message
webhook   = "https://example.com/hooks/contact"  # POSTs each submission as JSON

Заявка, не прошедшая required или types, не сохраняется; посетитель видит, что исправить, и ссылку назад. На бесплатном тарифе notify может быть только почтой вашего аккаунта, а webhook недоступен.

Чтение заявок

  • Страница «Заявки» в панели показывает заявки всех форм в одной таблице. Ищите по ним, фильтруйте по сайту и типу формы и переключайтесь на спам, чтобы увидеть, что отсеяли проверки. Заявка считается новой, пока вы её не откроете.
  • Каждое сообщение приходит на почту вашего аккаунта с Reply-To, указывающим на отправителя.
  • lobsite forms ls выводит список ваших форм; lobsite forms export contact --csv скачивает заявки одной формы. Экспорт в CSV на странице «Заявки» скачивает то, что показывает таблица.

На бесплатном тарифе формы работают в ограниченном режиме: месячная квота на сайт, уведомления только на почту аккаунта и без вебхуков. Тариф Standard добавляет вебхуки, любой подтверждённый адрес для уведомлений и снимает месячное ограничение. См. Ограничения.