Jeśli kiedykolwiek tworzyłeś formularz kontaktowy i obserwowałeś, jak cała strona przeładowuje się po kliknięciu "Wyślij" przez użytkownika, już wiesz, jak irytujące może być to doświadczenie. Używając technik wysyłania formularzy HTML z fetch i JavaScript, możesz przesyłać dane formularza do backendu w tle, utrzymać użytkownika na tej samej stronie i wyświetlić czytelny komunikat sukcesu lub błędu bez pełnego odświeżania strony. Ten tutorial przeprowadzi Cię przez każdy krok, od napisania podstawowego HTML-a po skierowanie wywołania fetch() na endpoint Sendform, dzięki czemu Twoje zgłoszenia trafią bezpośrednio do skrzynki odbiorczej lub podłączonego workflow.
Kluczowe informacje:
- Fetch API pozwala wysyłać dane formularza bez przeładowania strony, zapewniając użytkownikom płynniejsze doświadczenie.
- Przechwycenie zdarzenia
submiti wywołaniepreventDefault()to podstawa każdego wzorca wysyłania formularza przez AJAX. - Sendform dostarcza gotowy URL endpointu, więc nie potrzebujesz żadnego kodu backendowego do odbierania i przechowywania zgłoszeń.
- Właściwa obsługa odpowiedzi (pokazywanie informacji zwrotnej o sukcesie lub błędzie) jest równie ważna jak prawidłowe wysłanie danych.
Spis treści
Dlaczego używać fetch() zamiast domyślnego wysyłania formularza
Domyślne zachowanie przeglądarki przy wysyłaniu formularza robi dokładnie jedną rzecz: serializuje pola formularza, wysyła żądanie POST (lub GET) na URL określony w action, a następnie ładuje odpowiedź zwróconą przez serwer. To oznacza, że użytkownik widzi białe migotanie, traci pozycję przewijania i czeka na wyrenderowanie nowej strony. Przy wolnym połączeniu może to sprawić wrażenie zepsutego.
Fetch API rozwiązuje to poprzez programowe wykonywanie żądań HTTP, całkowicie w JavaScript, bez nawigowania. To umożliwia wysyłanie formularza bez przeładowania strony, co utrzymuje zaangażowanie użytkowników i pozwala kontrolować każdy aspekt doświadczenia użytkownika, włączając stany ładowania, walidację inline oraz animowane banery sukcesu.
Dodatkowe praktyczne powody, by preferować fetch():
- Możesz dołączać niestandardowe nagłówki (na przykład token CSRF czy klucz autoryzacji), których zwykły formularz HTML nie może wysłać.
- Możesz serializować dane jako JSON,
FormDatalub stringi zakodowane URL w zależności od tego, czego oczekuje endpoint. - Obsługa błędów jest jawna. To Ty decydujesz, co oznacza "niepowodzenie" i jak to komunikować.
- Działa na każdej statycznej stronie, włączając te hostowane na GitHub Pages, Netlify czy CDN, ponieważ logika znajduje się całkowicie w przeglądarce.
Uwaga: Jeśli pracujesz z builderem stron jak Webflow, WordPress czy Hugo, to samo podejście z fetch() się sprawdza. Zobacz nasz przewodnik o tym, jak zintegrować Sendform z builderem stron, aby poznać wskazówki specyficzne dla platformy.
Podstawowa konfiguracja formularza HTML
Przed napisaniem choćby jednej linijki JavaScript potrzebujesz dobrze ustrukturyzowanego formularza HTML. Kluczowym szczegółem jest to, że nie potrzebujesz atrybutu action wskazującego gdziekolwiek, ponieważ JavaScript obsłuży wysyłanie. Potrzebujesz jednak znaczących atrybutów name przy każdym input - stają się one kluczami pól w wysyłanym payloadzie.
<form id="contact-form" novalidate>
<div>
<label for="name">Twoje imię</label>
<input type="text" id="name" name="name" required placeholder="Jan Kowalski">
</div>
<div>
<label for="email">Adres email</label>
<input type="email" id="email" name="email" required placeholder="[email protected]">
</div>
<div>
<label for="message">Wiadomość</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<button type="submit">Wyślij wiadomość</button>
<!-- Obszar informacji zwrotnej -->
<div id="form-feedback" aria-live="polite"></div>
</form>Kilka rzeczy wartych uwagi w tym znaczniku:
novalidatena elemencie formularza wyłącza natywne dymki walidacji przeglądarki, dając Ci pełną kontrolę nad komunikatami błędów w JavaScript.- Div
id="form-feedback"zaria-live="polite"to miejsce, gdzie pojawią się komunikaty sukcesu i błędów. Atrybut ARIA zapewnia, że czytniki ekranu automatycznie ogłoszą informację zwrotną. - Każdy input ma zarówno
id(dla powiązania z label), jak iname(dla payloadu formularza).
Przechwytywanie zdarzenia submit
Pierwszym krokiem w każdym wysyłaniu formularza przez JavaScript jest przechwycenie domyślnego zachowania przeglądarki. Robisz to, nasłuchując zdarzenia submit na elemencie formularza i natychmiast wywołując event.preventDefault().
const form = document.getElementById('contact-form');
form.addEventListener('submit', async function (event) {
event.preventDefault(); // Zatrzymaj domyślną nawigację strony
// Podstawowa walidacja po stronie klienta
const name = form.elements['name'].value.trim();
const email = form.elements['email'].value.trim();
const message = form.elements['message'].value.trim();
if (!name || !email || !message) {
showFeedback('Proszę wypełnić wszystkie pola.', 'error');
return;
}
// Przejdź do wysyłania danych (następna sekcja)
await submitForm({ name, email, message });
});Oddzielając logikę walidacji od wywołania sieciowego, utrzymujesz kod czytelnym i łatwym do rozszerzenia. Słowo kluczowe async w handlerze zdarzenia pozwala używać await wewnątrz niego, co sprawia, że wywołanie Fetch API wygląda synchronicznie i unika głęboko zagnieżdżonych łańcuchów promise.
Kierowanie fetch() na endpoint Sendform
Tu dzieje się prawdziwa praca. Zamiast budować własny serwer do odbierania, przechowywania i przekazywania zgłoszeń formularzy, możesz użyć Sendform jako swojego backendu. Po utworzeniu formularza w panelu Sendform otrzymujesz unikalny URL endpointu. Ten URL to wszystko, czego potrzebujesz.
Poniższa funkcja wysyłania używa FormData API do budowania payloadu, który Sendform akceptuje natywnie:
async function submitForm(data) {
// Zastąp ten URL swoim rzeczywistym endpointem Sendform
const SENDFORM_ENDPOINT = 'https://sendform.net/pl/YOUR_FORM_ID';
const formData = new FormData();
formData.append('name', data.name);
formData.append('email', data.email);
formData.append('message', data.message);
try {
const response = await fetch(SENDFORM_ENDPOINT, {
method: 'POST',
body: formData,
});
if (response.ok) {
showFeedback('Dziękujemy! Twoja wiadomość została wysłana.', 'success');
form.reset();
} else {
const errorData = await response.json().catch(() => ({}));
const errorMsg = errorData.message || 'Coś poszło nie tak. Spróbuj ponownie.';
showFeedback(errorMsg, 'error');
}
} catch (networkError) {
showFeedback('Błąd sieci. Sprawdź połączenie i spróbuj ponownie.', 'error');
}
}Kluczowe decyzje podjęte w tym kodzie:
- Nagłówek
Content-Typenie jest ustawiany ręcznie. Gdy przekazujesz obiektFormDatajako body, przeglądarka automatycznie ustawia prawidłową granicęmultipart/form-data. - Sprawdzenie
response.okobejmuje wszystkie kody statusu HTTP 2xx, nie tylko 200. To jest bardziej niezawodne niż porównywanieresponse.status === 200. - Zewnętrzny
try/catchłapie błędy na poziomie sieci (błędy DNS, stan offline), którychresponse.oknigdy nie zobaczy.
Obsługa odpowiedzi - komunikaty sukcesu i błędów
Wysłanie danych to tylko połowa pracy. Użytkownicy potrzebują natychmiastowej, jasnej informacji zwrotnej. Funkcja pomocnicza showFeedback() wymieniona powyżej wpisuje komunikat do div-a feedback, który dodałeś do HTML-a:
function showFeedback(message, type) {
const feedbackEl = document.getElementById('form-feedback');
feedbackEl.textContent = message;
feedbackEl.className = type === 'success' ? 'feedback-success' : 'feedback-error';
}To jest celowo minimalne. W prawdziwym projekcie możesz zamienić textContent na animowany komponent lub bibliotekę powiadomień toast, ale wzorzec pozostaje ten sam: aktualizuj DOM na podstawie wyniku wywołania fetch().
Dla bardziej zaawansowanych scenariuszy, takich jak przekierowanie na niestandardową stronę podziękowania lub uruchomienie automatyzacji po zgłoszeniu, sprawdź nasz artykuł o tym, jak automatyzować workflow formularzy z webhook-ami, Zapier i API.
Najlepsze praktyki i wskazówki
Sprawienie, żeby kod działał to jedno. Wdrożenie go w sposób, który wytrzyma w produkcji to drugie. Oto najważniejsze wskazówki, które warto mieć na uwadze:
- Wyłącz przycisk submit podczas żądania. Ustaw
button.disabled = trueprzed wywołaniemfetch()i włącz ponownie w blokufinally. To zapobiega duplikacji zgłoszeń, jeśli użytkownik kliknie wielokrotnie. - Pokaż stan ładowania. Zmień tekst przycisku na "Wysyłanie..." lub dodaj klasę spinnera podczas trwania żądania. Użytkownicy, którzy nie widzą informacji zwrotnej, często zakładają, że nic się nie stało i klikają ponownie.
- Waliduj także po stronie serwera. Walidacja po stronie klienta służy doświadczeniu użytkownika. Sendform i każda usługa backendowa powinna traktować wszystkie przychodzące dane jako niezaufane.
- Używaj wszędzie HTTPS. Wysyłanie danych formularza przez zwykły HTTP naraża dane wejściowe użytkownika podczas transmisji. Endpointy Sendform są domyślnie HTTPS, ale upewnij się, że Twoja strona także jest serwowana przez HTTPS.
- Dodaj ochronę przed spamem. Pole honeypot lub integracja CAPTCHA znacząco redukuje śmieciowe zgłoszenia. Aby głębiej poznać ten temat, zobacz nasz przewodnik o najlepszych praktykach ochrony przed spamem w formularzach.
- Testuj celowo ścieżkę błędów. Tymczasowo zmień URL endpointu na coś nieprawidłowego i potwierdź, że pojawia się Twój komunikat błędu. Większość programistów testuje tylko ścieżkę sukcesu.
- Trzymaj URL endpointu poza kontrolą wersji. Jeśli Twój projekt jest open source, przechowuj endpoint Sendform w zmiennej środowiskowej lub pliku konfiguracyjnym, który jest wymieniony w
.gitignore.
Użytkownicy stron statycznych: Jeśli Twój projekt to strona Hugo, Eleventy czy zwykły HTML bez serwera, podejście z fetch() opisane tutaj jest zalecaną metodą. Przeczytaj więcej w naszym przewodniku po bezserwerowej obsłudze formularzy dla stron statycznych.
Podsumowanie
Zastąpienie domyślnego wysyłania formularza wywołaniem fetch() to jedna z najbardziej wpływowych poprawek, jakie możesz wprowadzić do każdego formularza kontaktowego czy przechwytywania leadów. Rezultatem jest szybsze, bardziej profesjonalne doświadczenie, które utrzymuje użytkowników na Twojej stronie i daje Ci pełną kontrolę nad komunikatami zwrotnymi. Połącz to z endpointem Sendform, a całkowicie wyeliminujesz potrzebę jakiegokolwiek kodu po stronie serwera. Twój formularz jest aktywny, Twoje zgłoszenia docierają do skrzynki odbiorczej, a użytkownicy nigdy nie widzą irytującego przeładowania strony. Utwórz swój darmowy endpoint Sendform już dziś i otrzymaj pierwsze zgłoszenie w ciągu minut.
Często zadawane pytania
Tak. Ponieważ fetch() działa całkowicie w przeglądarce, funkcjonuje na statycznych stronach HTML, projektach JAMstack i każdej platformie serwującej HTML. Nie potrzebujesz własnego serwera. Jedynym wymaganiem jest endpoint (jak URL Sendform), który może odbierać żądania POST.
fetch() to nowoczesne zastąpienie dla XMLHttpRequest. Używa Promise, wspiera async/await i ma czystsze API. W nowych projektach fetch() jest zawsze preferowane. Oba osiągają ten sam rezultat wysyłania formularza przez AJAX, ale fetch() wymaga znacznie mniej kodu boilerplate.
Nie. Gdy przekazujesz obiekt FormData jako body, przeglądarka automatycznie ustawia Content-Type na multipart/form-data i dołącza prawidłowy string granicy. Ustawienie go ręcznie faktycznie zepsułoby żądanie przez pominięcie tej wartości granicy.
Zarejestruj się w Sendform, utwórz nowy formularz w panelu i skopiuj wygenerowany URL endpointu. Wklej ten URL jako cel w swoim wywołaniu fetch(). Zgłoszenia będą natychmiast przekazywane na skonfigurowany adres email.
Błąd sieci powoduje odrzucenie Promise przez fetch(), co jest przechwytywane przez zewnętrzny blok try/catch w przykładowym kodzie. Użytkownik widzi komunikat "Błąd sieci", który zdefiniowałeś. Zgłoszenie nie jest automatycznie kolejkowane; użytkownik musi spróbować ponownie po przywróceniu łączności.