Formularze HTML: pola, etykiety, walidacja HTML5, GET i POST

INF.03 · teoria
autor: redakcja · 07.09.2026 · aktualizacja: 08.09.2026
Jak zbudować formularz na stronie: znacznik form z atrybutami action i method, pola input i ich typy, etykiety, listy wyboru, walidacja HTML5 oraz różnica między metodą GET i POST. Lekcja 3.7 kursu INF.03.
For­mu­larz to zestaw pól, w które użyt­kow­nik wpi­su­je dane, oraz przy­cisk, który wysyła te dane na serwer. Bez for­mu­la­rza strona tylko po­ka­zu­je treść: lo­go­wa­nie, wy­szu­ki­war­ka, ko­men­tarz i za­mó­wie­nie za­czy­na­ją się wła­śnie od niego. W części pi­sem­nej wra­ca­ją py­ta­nia z ry­sun­kiem („który kod dał ten zestaw kon­tro­lek", „co pokaże prze­glą­dar­ka po wy­sła­niu", „GET czy POST", „co robi required i pattern"). W za­da­niu prak­tycz­nym arkusz każe zwykle zrobić for­mu­larz wy­sy­ła­ny metodą POST do tej samej strony, z polami nu­me­rycz­ny­mi, przy­ci­skiem wy­sy­ła­ją­cym i przy­ci­skiem ka­su­ją­cym.

Znacz­nik form: dokąd i jaką metodą

<form> (FORMULARZ) to po­jem­nik obej­mu­ją­cy wszyst­kie pola na­le­żą­ce do jednej wy­sył­ki. Kon­tro­l­ka po­sta­wio­na poza nim wy­świe­tli się nor­mal­nie, ale nie wyśle ni­cze­go. O za­cho­wa­niu for­mu­la­rza de­cy­du­ją dwa atry­bu­ty.
  • action (adres celu) wska­zu­je plik, który od­bie­rze dane. Pusta war­tość action="" albo po­mi­nię­ty atry­but kie­ru­je dane pod adres bie­żą­cej strony, i do­kład­nie o to prosi arkusz CKE zda­niem „for­mu­larz prze­sy­ła­ją­cy dane do tego samego pliku".
  • method (metoda) wy­bie­ra sposób prze­sła­nia: get albo post. Po­mi­nię­ty method znaczy get.
Każde pole ma osobny atry­but name (nazwa). To klucz, pod którym serwer od­bie­ra wpi­sa­ną war­tość: pole name="imie" wy­sła­ne metodą POST czeka po stro­nie PHP pod $_POST['imie'], a wy­sła­ne metodą GET pod $_GET['imie']. Pole bez name nie jest w ogóle wy­sy­ła­ne, więc brak tego atry­bu­tu to naj­cich­szy błąd w całym for­mu­la­rzu. Od­bie­ra­niem i prze­twa­rza­niem danych zaj­mu­je się dział o PHP.
<form action="zamow.php" method="post"> <label for="imie">Imię</label> <input type="text" id="imie" name="imie"> <input type="submit" value="Zamów"> </form>
Metoda GET do­pi­su­je dane do adresu: po znaku za­py­ta­nia idą pary nazwa i war­tość, od­dzie­lo­ne zna­kiem &. Adres zamow.php?imie=Anna&ilosc=2 niesie całą treść for­mu­la­rza, więc widać ją w pasku prze­glą­dar­ki, można ją za­pi­sać w za­kład­ce i wysłać komuś od­no­śni­kiem, a dłu­gość adresu jest ogra­ni­czo­na. Metoda POST pakuje te same dane w treść żą­da­nia HTTP, której pasek adresu nie po­ka­zu­je i której roz­miar prak­tycz­nie nie ma limitu.
Formularz zamówienia i dwie drogi na serwer: GET dopisuje dane do adresu zamow.php?imie=Anna&ilosc=2, POST wysyła je w treści żądania
Cecha
GET
POST
Gdzie jadą dane
w ad­re­sie, po znaku za­py­ta­nia
w treści żą­da­nia
Widać je w pasku adresu
tak
nie
Za­kład­ka, hi­sto­ria, od­no­śnik
tak
nie
Limit dłu­go­ści
tak, adres ma ogra­ni­czo­ną dłu­gość
prak­tycz­nie brak
Wy­sył­ka pliku
nie
tak
Do czego
wy­szu­ki­wa­nie, filtry, od­no­śni­ki do wy­ni­ków
hasła, za­mó­wie­nia, zmiany w bazie
Odbiór w PHP
$_GET
$_POST
Ukry­cie danych w treści żą­da­nia to nie jest szy­fro­wa­nie. Wy­sła­ne zwy­kłym pro­to­ko­łem HTTP dane POST da się po­dej­rzeć w sieci tak samo jak GET, a po­uf­ność daje do­pie­ro HTTPS, więc py­ta­nie o naj­bez­piecz­niej­szy sposób wy­sła­nia danych po­uf­nych ma od­po­wiedź: metoda POST przez HTTPS. Oba pro­to­ko­ły opi­su­je lekcja Jak działa strona WWW.
Trzeci atry­but <form> po­ja­wia się tylko przy wy­sy­ła­niu plików: enctype="multipart/form-data" (wie­lo­czę­ścio­we dane for­mu­la­rza) każe po­dzie­lić żą­da­nie na części i wsta­wić w jedną z nich za­war­tość pliku. Bez tego atry­bu­tu pole wyboru pliku prze­śle samą nazwę, bez treści. Wy­sył­ka pliku wymaga też metody POST.

Pole input i jego typy

<input> (pole wej­ścio­we) to jeden znacz­nik, z któ­re­go atry­but type robi kil­ka­na­ście róż­nych kon­tro­lek. Znacz­nik nie ma części za­my­ka­ją­cej i w HTML5 pisze się go bez uko­śni­ka.
Typ
Do czego służy
Przy­kład
text
krótki tekst, typ do­myśl­ny
<input type="text" name="imie">
password
hasło, wpi­sy­wa­ne znaki są ma­sko­wa­ne
<input type="password" name="haslo">
email
adres poczty, spraw­dza­ny przez prze­glą­dar­kę
<input type="email" name="mail">
number
tylko liczby, z min, max i step
<input type="number" name="ilosc" min="1" max="10">
range
suwak w po­da­nym za­kre­sie
<input type="range" name="ocena" min="1" max="5">
date
data wy­bie­ra­na z ka­len­da­rza
<input type="date" name="dostawa">
time
go­dzi­na
<input type="time" name="odbior">
color
prób­nik koloru
<input type="color" name="kolor">
checkbox
pole wyboru, kilka za­zna­czeń naraz
<input type="checkbox" name="regulamin" checked>
radio
jedna opcja z kilku, wspól­ny name
<input type="radio" name="platnosc" value="karta">
file
wybór pliku do wy­sła­nia
<input type="file" name="zdjecie">
hidden
war­tość nie­wi­docz­na, wy­sy­ła­na razem z resztą
<input type="hidden" name="id" value="7">
submit
przy­cisk wy­sy­ła­ją­cy for­mu­larz
<input type="submit" value="Zamów">
reset
przy­cisk ka­su­ją­cy wpi­sa­ne dane
<input type="reset" value="Wyczyść">
button
przy­cisk bez wła­sne­go dzia­ła­nia, dla skryp­tu
<input type="button" value="Licz">
Przy­ci­ski opcji (radio) tworzą grupę przez WSPÓLNĄ war­tość name: tylko wtedy za­zna­cze­nie jed­ne­go od­zna­cza po­zo­sta­łe. Pola wyboru (checkbox) za­zna­cza się nie­za­leż­nie od siebie, więc każde może mieć własną nazwę. Atry­but checked za­zna­cza kon­tro­l­kę od razu po wczy­ta­niu strony, a value mówi, co poleci na serwer, bo napis sto­ją­cy obok kon­tro­l­ki jest tylko ety­kie­tą.
Atry­but
Co robi
name
klucz, pod którym serwer od­bie­ra war­tość pola
value
war­tość po­cząt­ko­wa, wy­sy­ła­na razem z for­mu­la­rzem
placeholder
szara pod­po­wiedź w pustym polu, znika po roz­po­czę­ciu pi­sa­nia
maxlength
naj­więk­sza liczba znaków, jaką da się wpisać
size
sze­ro­kość pola na ekra­nie, li­czo­na w zna­kach
readonly
war­tość wi­docz­na i wy­sy­ła­na, ale nie do zmiany
disabled
kon­tro­l­ka wy­sza­rzo­na i po­mi­ja­na przy wy­sył­ce
autofocus
kursor stoi w tym polu zaraz po wczy­ta­niu strony
Pu­łap­ka: maxlength ogra­ni­cza liczbę wpi­sa­nych znaków, size tylko sze­ro­kość pola na ekra­nie. Pole z maxlength="20" size="30" przyj­mie 20 znaków, a nie 30.

Ety­kie­ty, listy i grupy pól

<label> (ety­kie­ta) to podpis zwią­za­ny z kon­kret­ną kon­tro­l­ką. Wiąże się przez parę atry­bu­tów: for ety­kie­ty ma tę samą war­tość co id pola. Zysk jest po­dwój­ny. Klik­nię­cie w napis usta­wia kursor w polu, a przy checkbox i radio za­zna­cza kon­tro­l­kę, co przy małym kwa­dra­ci­ku na te­le­fo­nie ma spore zna­cze­nie. Czyt­nik ekranu od­czy­tu­je wtedy podpis razem z polem, więc osoba nie­wi­do­ma wie, co wpi­su­je. Wa­riant drugi to za­gnież­dże­nie: gdy kon­tro­l­ka stoi w środku znacz­ni­ka <label>, atry­bu­ty for i id nie są po­trzeb­ne.
<textarea> (obszar tekstu) to pole na dłuż­szy tekst, wy­so­kie na rows wier­szy i sze­ro­kie na cols znaków. Tekst po­cząt­ko­wy wpi­su­je się MIĘDZY znacz­ni­ki, nie w atry­but value. <select> (lista wyboru) tworzy listę roz­wi­ja­ną, a każdą po­zy­cję opi­su­je <option> (opcja). Na serwer leci value opcji, a nie jej wi­docz­ny napis, na­to­miast selected wska­zu­je po­zy­cję za­zna­czo­ną na star­cie. Atry­but size po­ka­zu­je kilka po­zy­cji naraz za­miast listy roz­wi­ja­nej, a multiple po­zwa­la za­zna­czyć kilka po­zy­cji jed­no­cze­śnie. <optgroup> z atry­bu­tem label dzieli długą listę na na­zwa­ne części.
<label for="uwagi">Uwagi do zamówienia</label> <textarea id="uwagi" name="uwagi" rows="4" cols="30"></textarea> <label for="dostawa">Dostawa</label> <select id="dostawa" name="dostawa"> <optgroup label="Kurier"> <option value="dpd">DPD</option> <option value="inpost" selected>InPost</option> </optgroup> <option value="odbior">Odbiór osobisty</option> </select>
<datalist> daje zwy­kłe­mu polu tek­sto­we­mu listę pod­po­wie­dzi, ale nie za­bra­nia wpisać czegoś spoza niej, i to od­róż­nia go od listy <select>. <fieldset> (zestaw pól) gru­pu­je po­wią­za­ne ze sobą kon­tro­l­ki i rysuje wokół nich ramkę, a <legend> pod­pi­su­je tę grupę.
<button> (przy­cisk) robi to samo co input typu przy­cisk, tylko treść bierze spo­mię­dzy znacz­ni­ków, więc mieści obraz albo po­gru­bio­ne słowo. Jego atry­but type przyj­mu­je submit (wysyła, war­tość do­myśl­na), reset (kasuje) oraz button (przy­cisk bez wła­sne­go dzia­ła­nia, cze­ka­ją­cy na skrypt JavaScript). <output> po­ka­zu­je wynik wy­li­czo­ny skryp­tem, na przy­kład kwotę za­mó­wie­nia po­li­czo­ną z ilości i ceny.

Wa­li­da­cja HTML5

Wa­li­da­cja for­mu­la­rza to spraw­dze­nie, czy wpro­wa­dzo­ne dane speł­nia­ją okre­ślo­ne reguły. HTML5 po­tra­fi to zrobić bez żad­ne­go skryp­tu: przy próbie wy­sła­nia prze­glą­dar­ka za­trzy­mu­je for­mu­larz, usta­wia kursor w błęd­nym polu i wy­świe­tla przy nim dymek z ko­mu­ni­ka­tem.
Zapis
Co spraw­dza
required
pole nie może zostać puste
type="email"
war­tość wy­glą­da jak adres poczty, czyli za­wie­ra znak @
type="number" z min i max
tylko liczba i tylko z po­da­ne­go za­kre­su
step
co ile wolno zmie­niać war­tość, na przy­kład step="0.5"
minlength, maxlength
naj­mniej­sza i naj­więk­sza liczba znaków
pattern="[0-9]{2}-[0-9]{3}"
war­tość pasuje do wy­ra­że­nia re­gu­lar­ne­go
title="Format 00-000"
tekst do­pi­sa­ny do ko­mu­ni­ka­tu o błę­dzie
novalidate w <form>
wy­łą­cza całe spraw­dza­nie przy wy­sył­ce
Wy­ra­że­nie re­gu­lar­ne [0-9]{2}-[0-9]{3} czyta się ka­wa­łek po ka­wał­ku: [0-9] to jedna cyfra, {2} to do­kład­nie dwa takie znaki, potem zwykły dywiz, potem trzy cyfry. Wzo­rzec musi pa­so­wać do CAŁEJ war­to­ści, więc 12-345 prze­cho­dzi, a 12-3456 już nie.
<label for="kod">Kod pocztowy</label> <input type="text" id="kod" name="kod" required pattern="[0-9]{2}-[0-9]{3}" title="Format 00-000">
Spraw­dza­nie w prze­glą­dar­ce jest wygodą dla użyt­kow­ni­ka, a nie za­bez­pie­cze­niem: dane da się wysłać z po­mi­nię­ciem strony, więc te same reguły muszą po­wtó­rzyć się w skryp­cie po stro­nie ser­we­ra. Osobna sprawa to spraw­dza­nie w trak­cie pi­sa­nia, znak po znaku, z ko­mu­ni­ka­tem obok pola: tego atry­bu­ty HTML5 nie robią, pisze się to w języku JavaScript.

For­mu­larz za­mó­wie­nia w skle­pie

Strona sklepu kom­pu­te­ro­we­go z po­przed­nich lekcji do­sta­je for­mu­larz za­mó­wie­nia w bloku treści, pod listą pro­duk­tów i tabelą cen.
<form action="" method="post"> <fieldset> <legend>Zamówienie</legend> <label for="imie">Imię i nazwisko</label> <input type="text" id="imie" name="imie" required maxlength="40"> <label for="produkt">Produkt</label> <select id="produkt" name="produkt"> <option value="klawiatura">Klawiatura</option> <option value="mysz" selected>Mysz</option> <option value="monitor24">Monitor 24</option> </select> <label for="ilosc">Ilość</label> <input type="number" id="ilosc" name="ilosc" min="1" max="10" value="1"> <input type="submit" value="Zamów"> <input type="reset" value="Wyczyść"> </fieldset> </form>
W prze­glą­dar­ce widać ramkę z na­pi­sem „Za­mó­wie­nie" wpi­sa­nym w jej górną kra­wędź, a w środku pod­pi­sa­ne pole tek­sto­we, listę roz­wi­ja­ną z trzema pro­duk­ta­mi (od razu wy­bra­na jest Mysz), pole licz­bo­we ze strzał­ka­mi i war­to­ścią 1 oraz dwa przy­ci­ski. Na­ci­śnię­cie przy­ci­sku „Zamów" z pustym imie­niem nie wysyła ni­cze­go: prze­glą­dar­ka po­ka­zu­je dymek przy pierw­szym błęd­nym polu. Po po­praw­nym wy­peł­nie­niu strona wczy­tu­je się po­now­nie pod tym samym ad­re­sem, bo action jest puste, a pasek adresu nie zmie­nia się, bo metodą jest POST. Przy­cisk „Wy­czyść" przy­wra­ca war­to­ści po­cząt­ko­we, czyli puste imię, Mysz i 1.
Pu­łap­ka: reset przy­wra­ca war­to­ści POCZĄTKOWE za­pi­sa­ne w kodzie, a nie puste pola. Pole z value="1" po wy­czysz­cze­niu znowu po­ka­zu­je 1.

Na eg­za­mi­nie

Py­ta­nia pi­sem­ne o for­mu­la­rze mają kilka sta­łych kształ­tów. Ry­su­nek z ze­sta­wem kon­tro­lek i cztery bloki kodu do wyboru: policz kon­tro­l­ki i sprawdź, które są polami tek­sto­wy­mi, która listą, a które przy­ci­ska­mi. Frag­ment kodu z jednym polem i py­ta­nie, co o nim wia­do­mo: type="password" ukrywa wpi­sy­wa­ne znaki, type="number" przyj­mu­je wy­łącz­nie war­to­ści licz­bo­we, readonly po­ka­zu­je war­tość bez moż­li­wo­ści zmiany. Py­ta­nie o gru­po­wa­nie: po­wią­za­ne ze sobą ele­men­ty for­mu­la­rza gru­pu­je <fieldset>, a nie <optgroup>, który obej­mu­je wy­łącz­nie opcje listy. Py­ta­nie o wa­li­da­cję: pole z required i wzor­cem wy­ma­ga­ją­cym znaku @ znaczy „nie może być puste i wymaga tekstu ze zna­kiem @". Py­ta­nie z ad­re­sem po wy­sła­niu: skoro w pasku widać ?imie=Anna, metodą była GET, a dane cze­ka­ją w ta­bli­cy $_GET.
Kilka od­po­wie­dzi myli się re­gu­lar­nie. placeholder to pod­po­wiedź w polu, zni­ka­ją­ca po roz­po­czę­ciu pi­sa­nia, a value to war­tość do­myśl­na, która w polu zo­sta­je i zo­sta­nie wy­sła­na. Kilka za­zna­czeń naraz daje checkbox, jedno z kilku daje radio ze wspól­nym name, a wie­lo­krot­ny wybór z listy roz­wi­ja­nej włącza atry­but multiple w znacz­ni­ku <select>. Wa­li­da­cja to spraw­dze­nie, czy wpro­wa­dzo­ne dane speł­nia­ją okre­ślo­ne reguły, a nie spraw­dze­nie, kto je wpro­wa­dził ani czy plik od­bie­ra­ją­cy ist­nie­je.
W za­da­niu prak­tycz­nym po­le­ce­nie brzmi zwykle: for­mu­larz wy­sy­ła­ny metodą POST do tego samego pliku, z polami nu­me­rycz­ny­mi, przy­ci­skiem wy­sy­ła­ją­cym i przy­ci­skiem ka­su­ją­cym. Tłu­ma­czy się je punkt po punk­cie. „Metoda POST do tego samego pliku" to method="post" i action="", „pole nu­me­rycz­ne" to type="number", „przy­cisk wy­sy­ła­ją­cy" to type="submit", „przy­cisk ka­su­ją­cy" to type="reset". Nazwy pól muszą zga­dzać się co do znaku z tym, czego szuka skrypt PHP do­łą­czo­ny do ar­ku­sza: name="ilosc" po stro­nie strony i $_POST['ilosc'] po stro­nie skryp­tu. Każde pole do­sta­je ety­kie­tę, bo oce­nia­na jest za­war­tość wi­try­ny, a sam napis obok kon­tro­l­ki pod­pi­sem nie jest. Eg­za­mi­na­tor klika po go­to­wej stro­nie, więc for­mu­larz musi się wy­świe­tlić i za­re­ago­wać na oba przy­ci­ski.

Ściąga

Zapis
Znaczy
<form action="" method="post">
for­mu­larz wy­sy­ła­ny metodą POST do tej samej strony
method="get"
dane w ad­re­sie, wi­docz­ne, można je za­pi­sać w za­kład­ce
<input type="text" name="imie">
pole tek­sto­we, name to klucz od­bio­ru na ser­we­rze
<input type="number" min="1" max="10">
pole nu­me­rycz­ne z za­kre­sem war­to­ści
<input type="password">
pole hasła, ma­sku­je wpi­sy­wa­ne znaki
<input type="submit" value="Zamów">
przy­cisk wy­sy­ła­ją­cy for­mu­larz
<input type="reset" value="Wyczyść">
przy­cisk przy­wra­ca­ją­cy war­to­ści po­cząt­ko­we
<label for="imie">
ety­kie­ta pola o id="imie", kli­kal­na
<select> z <option value="mysz">
lista roz­wi­ja­na, selected to opcja do­myśl­na
<fieldset> z <legend>
gru­pu­je po­wią­za­ne kon­tro­l­ki i pod­pi­su­je grupę
required
pole nie może zostać puste
pattern="[0-9]{2}-[0-9]{3}"
war­tość musi pa­so­wać do wzorca, tu kod pocz­to­wy
Pobierz ściągę PDF
ZAWODNIK
egzamin zawodowy INF.02 · INF.03 · INF.04
Serwer Discord
Egzaminy zawodowe IT/Matury/Studia
@yastor
© 2026 Zawodnik · by Yastor
Arkusze i zasady oceniania pochodzą z CKE. Serwis nie jest powiązany z Centralną Komisją Egzaminacyjną.