Potwierdzone sprawdzone punkt po punkcie · 2026-11-05
Pomiń nawigację
Informatyka · INF.03

HTML I CSS · INF.03 · MODUŁ 05

Formularze

Formularz to rozmowa z użytkownikiem. Każde pole powinno mieć etykietę, typ i jasny cel.

Wprowadzenie

Formularz to część strony, w której użytkownik podaje dane: loguje się, wypełnia ankietę albo składa zamówienie. Całość zamykasz w elemencie <form>. Atrybut action wskazuje adres, który otrzyma dane, a method — sposób ich przesłania.

method="get" dopisuje dane do adresu strony, np. /szukaj?q=html. Nadaje się do wyszukiwania i filtrów, ale nie do haseł. method="post" wysyła dane w treści żądania, więc nie widać ich w pasku adresu. Logowanie, rejestracja i zamówienie powinny używać post.

Każde pole powinno mieć etykietę <label> połączoną z polem przez for i id. Dzięki temu kliknięcie w tekst etykiety ustawia kursor w polu, a czytnik ekranu odczytuje nazwę pola. Sam placeholder nie wystarcza, bo znika po wpisaniu tekstu.

Atrybut name jest nazwą pola w danych wysyłanych na serwer. Bez name pole nie trafi do formularza, nawet jeśli użytkownik coś w nim wpisze. Para name=value to najmniejsza jednostka danych formularza.

Etykieta, nie placeholder

placeholder to tylko podpowiedź, a nie nazwa pola. Każde pole tekstowe, e-mail, hasło, listę i obszar tekstowy opisz przez <label for="...">.

1. Do czego służy atrybut action w elemencie form?
1. Do czego służy atrybut action w elemencie form?
2. Który atrybut decyduje o tym, pod jaką nazwą pole zostanie wysłane na serwer?
2. Który atrybut decyduje o tym, pod jaką nazwą pole zostanie wysłane na serwer?
3. Które połączenie etykiety z polem jest poprawne?
3. Które połączenie etykiety z polem jest poprawne?

Najważniejsza własność

Formularz wysyła na serwer pary name=value. Atrybut name mówi, pod jakim kluczem zapisać wartość, a value — co dokładnie zostanie wysłane. Pola bez name są pomijane. To najważniejsza zasada: najpierw nazwij pole, potem myśl o jego wyglądzie.

Para danych

name="email" + value="ala@example.com" → email=ala%40example.com

method="post" ukrywa dane w adresie, a method="get" dopisuje je po znaku ?.

Rodzaj pola wybierasz atrybutem type. Przeglądarka dobiera do niego klawiaturę, sposób wyświetlania i podstawową walidację. To nie zastępuje sprawdzenia danych na serwerze, ale szybko informuje użytkownika o pomyłce.

Typ polaDo czego służyNa co uważać
textkrótki tekst, np. imięnie sprawdza formatu
emailadres e-mailwymaga znaku @ i domeny
passwordhasłozasłania znaki, ale nie szyfruje transmisji
numberliczba, np. liczba sztukzakres ustawiasz przez min i max
datedatawartość ma format RRRR-MM-DD
telnumer telefonunie sprawdza formatu — dodaj pattern
urladres strony internetowejoczekuje http:// lub https://
searchpole wyszukiwaniasemantycznie sygnalizuje szukanie
radiojeden wybór z grupywszystkie opcje mają wspólne name
checkboxzero, jeden lub kilka wyborówwartość jest wysyłana tylko po zaznaczeniu
fileplik z komputeraformularz wymaga enctype="multipart/form-data"
rangesuwak z zakresemzakres i krok ustawiasz przez min, max, step
colorwybór koloruwartość zapisuje się jako #rrggbb
hiddendane techniczne niewidoczne dla użytkownikanie jest zabezpieczeniem — można je zmienić

Poza polami <input> masz jeszcze cztery ważne elementy. <select> z <option> tworzy listę rozwijaną. <textarea> pozwala wpisać wiele linii — tekst początkowy umieszczasz między tagami, a nie w atrybucie value. <button type="submit"> wysyła formularz, a type="button" tylko wykonuje akcję. <fieldset> z <legend> grupuje powiązane pola i nadaje grupie nazwę.

Walidację po stronie przeglądarki ustawiasz atrybutami: required (pole musi być wypełnione), min i max (zakres liczby lub daty), minlength i maxlength (długość tekstu), pattern (wyrażenie regularne, np. [0-9]{9} oznacza dokładnie dziewięć cyfr) oraz autocomplete (podpowiedź dla przeglądarki, np. email albo current-password).

required to nie bezpieczeństwo

Atrybut required działa tylko w przeglądarce i można go obejść. Zawsze sprawdzaj dane ponownie na serwerze — zwłaszcza e-mail, liczbę sztuk i zgodę na regulamin.

Most: od teorii do kodu

Uzupełnij formularz logowania

Wybierz brakujące atrybuty. Formularz ma wysłać e-mail i hasło metodą POST, a oba pola mają być wymagane.

Brakujące atrybuty

uzupełnianie luk

Uzupełnij cztery luki.

<form action="/logowanie" method="">
  <label ="email">E-mail</label>
  <input type="email" id="email" ="email" required>
  <label for="haslo">Hasło</label>
  <input type="" id="haslo" name="haslo" required>
  <button type="submit">Zaloguj</button>
</form>

Znajdź błędy w formularzu

zaznaczanie

Zaznacz trzy linie, w których jest błąd.

4. Pole ma zapis <input type="email" name="email" value="ala@example.com">. Jaka para danych trafi do serwera?
4. Pole ma zapis <input type="email" name="email" value="ala@example.com">. Jaka para danych trafi do serwera?
5. Który typ pola najlepiej nadaje się do numeru telefonu, jeśli chcesz wymusić dokładnie 9 cyfr?
5. Który typ pola najlepiej nadaje się do numeru telefonu, jeśli chcesz wymusić dokładnie 9 cyfr?
6. Co robi atrybut required na polu formularza?
6. Co robi atrybut required na polu formularza?

Przykłady

Trzy formularze pokazują typowe sytuacje egzaminacyjne: logowanie, ankietę i zamówienie. W każdym zwróć uwagę na etykiety, atrybut name i sposób wysłania danych.

Przykład 1 — logowanie

Zbuduj formularz logowania z etykietami, polami e-mail i hasło oraz przyciskiem. Oba pola mają być wymagane, a dane mają iść metodą POST.

HTML
<form class="logowanie" action="/logowanie" method="post">
  <h2>Zaloguj się</h2>

  <p>
    <label for="email">Adres e-mail</label>
    <input type="email" id="email" name="email"
           autocomplete="email" placeholder="ala@example.com" required>
  </p>

  <p>
    <label for="haslo">Hasło</label>
    <input type="password" id="haslo" name="haslo"
           minlength="8" autocomplete="current-password" required>
  </p>

  <p>
    <button type="submit">Zaloguj</button>
  </p>
</form>
CSS
.logowanie {
  max-width: 380px;
  margin: 0 auto;
  padding: 24px;
  border: 1px solid #e2e8f0;
  border-radius: 14px;
  background: #fff;
}
.logowanie h2 {
  margin: 0 0 18px;
}
.logowanie p {
  margin: 0 0 16px;
}
.logowanie label {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
}
.logowanie input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid #94a3b8;
  border-radius: 8px;
  font: inherit;
}
.logowanie input:focus {
  outline: 3px solid #2563eb;
  outline-offset: 2px;
  border-color: #2563eb;
}
.logowanie button {
  padding: 10px 18px;
  border: 0;
  border-radius: 8px;
  background: #2563eb;
  color: #fff;
  font: inherit;
  cursor: pointer;
}
Formularz logowania z polami Adres e-mail i Hasło oraz przyciskiem Zaloguj
Efekt kodu: etykiety nad polami, podpowiedzi w polach i czytelny układ formularza.
  1. action="/logowanie" wskazuje adres, a method="post" ukrywa dane w adresie.
  2. label for="email" łączy się z input id="email" — kliknięcie w etykietę ustawia kursor w polu.
  3. type="email" uruchamia podstawową walidację adresu, a required blokuje wysłanie pustego pola.
  4. minlength="8" wymaga co najmniej ośmiu znaków hasła. autocomplete pomaga przeglądarce podpowiedzieć zapisane dane.

Wynik: formularz wysyła parę email=... i haslo=... metodą POST; przeglądarka pilnuje pustych pól i formatu e-maila.

Przykład 2 — ankieta

Zbierz odpowiedzi przez radio, checkbox, listę rozwijaną i obszar tekstowy. Pogrupuj powiązane pola w fieldset z legend.

HTML
<form class="ankieta" action="/ankieta" method="post">
  <fieldset>
    <legend>Jak często uczysz się HTML?</legend>
    <label><input type="radio" name="czestotliwosc"
      value="codziennie" required> codziennie</label>
    <label><input type="radio" name="czestotliwosc"
      value="tydzien"> raz w tygodniu</label>
    <label><input type="radio" name="czestotliwosc"
      value="rzadko"> rzadko</label>
  </fieldset>

  <fieldset>
    <legend>Które tematy chcesz powtórzyć?</legend>
    <label><input type="checkbox" name="tematy"
      value="formularze"> formularze</label>
    <label><input type="checkbox" name="tematy"
      value="tabele"> tabele</label>
    <label><input type="checkbox" name="tematy"
      value="grid"> grid</label>
  </fieldset>

  <p>
    <label for="poziom">Poziom zaawansowania</label>
    <select id="poziom" name="poziom">
      <option value="">— wybierz —</option>
      <option value="podstawowy">podstawowy</option>
      <option value="sredni">średni</option>
      <option value="zaawansowany">zaawansowany</option>
    </select>
  </p>

  <p>
    <label for="uwagi">Uwagi</label>
    <textarea id="uwagi" name="uwagi" rows="3"></textarea>
  </p>

  <button type="submit">Wyślij ankietę</button>
</form>
CSS
.ankieta {
  max-width: 640px;
  margin: 0 auto;
}
.ankieta fieldset {
  margin: 0 0 18px;
  padding: 12px 16px 14px;
  border: 1px solid #cbd5e1;
  border-radius: 10px;
}
.ankieta legend {
  padding: 0 6px;
  font-weight: 700;
}
.ankieta label {
  display: block;
  margin: 6px 0;
}
.ankieta p {
  margin: 0 0 16px;
}
.ankieta select,
.ankieta textarea {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid #94a3b8;
  border-radius: 8px;
  font: inherit;
}
.ankieta button {
  padding: 10px 18px;
  border: 0;
  border-radius: 8px;
  background: #2563eb;
  color: #fff;
  font: inherit;
  cursor: pointer;
}
Ankieta z dwoma grupami pól radio i checkbox, listą rozwijaną, obszarem tekstowym i przyciskiem Wyślij ankietę
Efekt kodu: dwie grupy w fieldset z legendami, lista rozwijana i pole wielolinijkowe.
  1. Wszystkie opcje radio w jednej grupie mają to samo name="czestotliwosc" — dlatego można wybrać tylko jedną.
  2. Checkboxy mają wspólne name="tematy", ale różne value — można zaznaczyć kilka i serwer dostanie kilka wartości.
  3. fieldset i legend opisują całą grupę, więc czytnik ekranu odczyta kontekst przed każdą opcją.
  4. select ma pustą opcję zachęty, a textarea nie ma atrybutu value — tekst wpisuje się między tagami.

Wynik: ankieta wysyła jedną wartość czestotliwosc, wybrane wartości tematy, poziom i treść uwag.

Przykład 3 — zamówienie w CSS Grid

Ułóż formularz zamówienia w dwóch kolumnach. Użyj pól number, date, tel, range, color i file, a focus zaznacz wyraźną obwódką.

HTML
<form class="zamowienie" action="/zamowienie" method="post"
      enctype="multipart/form-data">
  <h2>Zamówienie</h2>

  <p class="pole">
    <label for="imie">Imię i nazwisko</label>
    <input type="text" id="imie" name="imie"
           autocomplete="name" autofocus required>
  </p>

  <p class="pole">
    <label for="email">Adres e-mail</label>
    <input type="email" id="email" name="email"
           autocomplete="email" required>
  </p>

  <p class="pole">
    <label for="telefon">Telefon</label>
    <input type="tel" id="telefon" name="telefon"
           pattern="[0-9]{9}" placeholder="123456789" required>
  </p>

  <p class="pole">
    <label for="data">Data odbioru</label>
    <input type="date" id="data" name="data" required>
  </p>

  <p class="pole">
    <label for="ilosc">Liczba sztuk</label>
    <input type="number" id="ilosc" name="ilosc"
           min="1" max="10" value="1" required>
  </p>

  <p class="pole">
    <label for="kolor">Kolor</label>
    <input type="color" id="kolor" name="kolor" value="#2563eb">
  </p>

  <p class="pole">
    <label for="zakres">Zakres</label>
    <input type="range" id="zakres" name="zakres"
           min="0" max="100" value="50">
  </p>

  <p class="pole">
    <label for="plik">Projekt do wydruku</label>
    <input type="file" id="plik" name="plik"
           accept="image/png,image/jpeg">
  </p>

  <p class="pole pelna">
    <label for="uwagi">Uwagi</label>
    <textarea id="uwagi" name="uwagi" rows="3"></textarea>
  </p>

  <input type="hidden" name="zrodlo" value="kurs">

  <p class="pelna">
    <button type="submit">Złóż zamówienie</button>
  </p>
</form>
CSS
.zamowienie {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 20px;
  max-width: 720px;
  margin: 0 auto;
}
.zamowienie h2,
.zamowienie .pelna {
  grid-column: 1 / -1;
}
.zamowienie h2 {
  margin: 0;
}
.zamowienie .pole {
  display: grid;
  gap: 6px;
  margin: 0;
}
.zamowienie label {
  font-weight: 600;
}
.zamowienie input,
.zamowienie select,
.zamowienie textarea {
  padding: 10px 12px;
  border: 1px solid #94a3b8;
  border-radius: 8px;
  font: inherit;
}
.zamowienie input:focus,
.zamowienie select:focus,
.zamowienie textarea:focus {
  outline: 3px solid #2563eb;
  outline-offset: 2px;
  border-color: #2563eb;
}
.zamowienie input[type="color"] {
  height: 44px;
  padding: 4px;
}
.zamowienie button {
  padding: 10px 18px;
  border: 0;
  border-radius: 8px;
  background: #2563eb;
  color: #fff;
  font: inherit;
  cursor: pointer;
}
Formularz zamówienia w dwóch kolumnach z polami tekstowymi, datą, liczbą sztuk, kolorem, suwakiem, plikiem i widocznym focusem
Efekt kodu: siatka dwóch kolumn, pola w równych rzędach i niebieska obwódka w aktywnym polu.
  1. display: grid i grid-template-columns: 1fr 1fr tworzą dwie równe kolumny.
  2. Elementy z klasą .pelna oraz nagłówek rozciągają się przez obie kolumny dzięki grid-column: 1 / -1.
  3. type="number" z min="1" max="10" ogranicza liczbę sztuk, a pattern="[0-9]{9}" wymaga dziewięciu cyfr telefonu.
  4. enctype="multipart/form-data" jest potrzebne, gdy formularz wysyła plik. autofocus ustawia focus w pierwszym polu, dlatego widać obwódkę.

Wynik: formularz układa pola w siatce, pokazuje focus i wysyła dane oraz plik metodą POST.

Most: od teorii do kodu

Oceń formularz ankiety

Przeczytaj każdą linię i wybierz kategorię. Nie każda linia jest błędna.

Code review formularza

code review

Oceń każdą linię.

7. W grupie pól radio wszystkie opcje muszą mieć:
7. W grupie pól radio wszystkie opcje muszą mieć:
8. Który element tworzy pole tekstowe na wiele linii?
8. Który element tworzy pole tekstowe na wiele linii?
9. Której metody należy użyć w formularzu logowania, aby hasło nie pojawiło się w adresie strony?
9. Której metody należy użyć w formularzu logowania, aby hasło nie pojawiło się w adresie strony?

Spróbuj samodzielnie

Zanim napiszesz własny formularz, sprawdź, co przeglądarka wysyła po kliknięciu przycisku. Potem wykonaj zadania — od najprostszego do egzaminacyjnego.

Most: od teorii do kodu

Co trafi do adresu?

Formularz używa metody GET. Sprawdź, jak będą wyglądać dane po wysłaniu.

Adres po wysłaniu formularza

przewidywanie

Który adres otworzy przeglądarka po wysłaniu formularza?

<form action="/szukaj" method="get">
  <input type="search" name="q" value="html css">
  <input type="hidden" name="dzial" value="kursy">
  <button type="submit">Szukaj</button>
</form>
  1. Zadanie 1 — newsletter. Napisz formularz zapisu do newslettera: pole e-mail z etykietą, przycisk „Zapisz się”, wymagane pole i wysyłka metodą POST do /newsletter.

    Pokaż rozwiązanie

    Najpierw łączymy etykietę z polem przez for i id. Potem dodajemy name, type="email" i required. Całość wysyłamy metodą POST.

    <form action="/newsletter" method="post">
      <label for="email">Adres e-mail</label>
      <input type="email" id="email" name="email"
             autocomplete="email" required>
      <button type="submit">Zapisz się</button>
    </form>

    Etykieta jest powiązana z polem, więc kliknięcie w tekst ustawia kursor. required blokuje wysłanie pustego pola, ale serwer i tak musi sprawdzić adres ponownie.

  2. Zadanie 2 — ankieta. Zbuduj ankietę z trzema opcjami radio („tak”, „nie”, „nie wiem”) w grupie „Czy znasz formularze?”, dwoma checkboxami tematów oraz listą rozwijaną poziomu. Użyj fieldset i legend.

    Pokaż rozwiązanie

    Wszystkie radio muszą mieć to samo name, np. znasz. Checkboxy mogą mieć wspólne name="tematy" i różne value. Grupy zamykamy w fieldset z legend.

    <form action="/ankieta" method="post">
      <fieldset>
        <legend>Czy znasz formularze?</legend>
        <label><input type="radio" name="znasz" value="tak" required> tak</label>
        <label><input type="radio" name="znasz" value="nie"> nie</label>
        <label><input type="radio" name="znasz" value="nie-wiem"> nie wiem</label>
      </fieldset>
      <fieldset>
        <legend>Tematy do powtórki</legend>
        <label><input type="checkbox" name="tematy" value="formularze"> formularze</label>
        <label><input type="checkbox" name="tematy" value="grid"> grid</label>
      </fieldset>
      <p>
        <label for="poziom">Poziom</label>
        <select id="poziom" name="poziom">
          <option value="">— wybierz —</option>
          <option value="podstawowy">podstawowy</option>
          <option value="sredni">średni</option>
        </select>
      </p>
      <button type="submit">Wyślij</button>
    </form>
  3. Zadanie 3 — znajdź błędy. Uczeń napisał formularz poniżej. Wskaż trzy błędy i popraw je: brakujące name, złą etykietę i tekst w textarea.

    <form action="/zapis" method="post">
      <label for="email">Telefon</label>
      <input type="text" id="telefon">
      <textarea name="uwagi" value="Brak uwag"></textarea>
      <button type="submit">Wyślij</button>
    </form>
    Pokaż rozwiązanie

    Poprawki: etykieta musi wskazywać for="telefon", pole musi mieć name="telefon", a tekst początkowy w textarea wpisujemy między tagami.

    <form action="/zapis" method="post">
      <label for="telefon">Telefon</label>
      <input type="text" id="telefon" name="telefon">
      <textarea name="uwagi">Brak uwag</textarea>
      <button type="submit">Wyślij</button>
    </form>

    Metoda rozwiązania: najpierw sprawdź, czy każda etykieta ma for równe id pola. Potem sprawdź, czy każde pole ma name. Na końcu zajrzyj do elementów, które mają własną treść — textarea i button.

  4. Zadanie 4 — zamówienie. Zaprojektuj formularz zamówienia: imię, e-mail, telefon z pattern na 9 cyfr, liczbę sztuk od 1 do 5, datę odbioru i zgodę na regulamin. Ułóż pola w dwóch kolumnach przez CSS Grid i wyjaśnij, dlaczego używasz POST.

    Pokaż rozwiązanie

    Formularz ma dwa pola w każdym rzędzie. Pola imienia i e-maila mogą być w pierwszym rzędzie, telefon i data w drugim, liczba sztuk i zgoda w trzecim. Przycisk zajmuje całą szerokość.

    <form class="zamowienie" action="/zamowienie" method="post">
      <p class="pole">
        <label for="imie">Imię</label>
        <input type="text" id="imie" name="imie" required>
      </p>
      <p class="pole">
        <label for="email">E-mail</label>
        <input type="email" id="email" name="email" required>
      </p>
      <p class="pole">
        <label for="telefon">Telefon</label>
        <input type="tel" id="telefon" name="telefon"
               pattern="[0-9]{9}" required>
      </p>
      <p class="pole">
        <label for="data">Data odbioru</label>
        <input type="date" id="data" name="data" required>
      </p>
      <p class="pole">
        <label for="ilosc">Liczba sztuk</label>
        <input type="number" id="ilosc" name="ilosc"
               min="1" max="5" value="1" required>
      </p>
      <p class="pole">
        <label><input type="checkbox" name="regulamin"
          value="tak" required> Akceptuję regulamin</label>
      </p>
      <p class="pelna">
        <button type="submit">Zamów</button>
      </p>
    </form>
    .zamowienie {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 16px 20px;
    }
    .zamowienie .pelna {
      grid-column: 1 / -1;
    }
    .zamowienie .pole {
      display: grid;
      gap: 6px;
      margin: 0;
    }

    POST jest lepszy, bo zamówienie zawiera dane kontaktowe i nie powinno trafiać do adresu strony ani historii przeglądarki. required pilnuje pustych pól w przeglądarce, a min, max i pattern zawężają wartości — ale serwer nadal musi je sprawdzić.

Podsumowanie. Formularz wysyła pary name=value na adres z action, metodą get lub post. Każde pole nazwij przez name, połącz z etykietą przez for i id, a grupę pól zamknij w fieldset z legend. Walidacja w przeglądarce (required, min, max, pattern) pomaga użytkownikowi, ale nie zastępuje sprawdzenia na serwerze.

10. Pole <input type="email" id="email"> nie ma atrybutu name. Co się stanie po wysłaniu formularza?
10. Pole <input type="email" id="email"> nie ma atrybutu name. Co się stanie po wysłaniu formularza?
11. Jak poprawnie ustawić początkową treść pola textarea?
11. Jak poprawnie ustawić początkową treść pola textarea?
12. Co oznacza pattern="[0-9]{9}"?
12. Co oznacza pattern="[0-9]{9}"?