JSX to rozszerzenie składni JavaScriptu pozwalające zapisywać strukturę interfejsu użytkownika w formie przypominającej znane z HTML-a znaczniki, ale zachowujące pełną ekspresyjność i możliwości języka. Najważniejsza idea polega na tym, że zapis przypominający znacznik jest w rzeczywistości wyrażeniem JavaScript, które może być wynikiem obliczeń, zawierać zmienne, funkcje, operatory warunkowe i pętle zmapowane na wartości. W praktyce JSX jest najczęściej kojarzone z biblioteką React, lecz nie jest do niej ograniczone: ten sam zapis wspierają różne biblioteki i kompilatory, które przekształcają składnię znacznikową na zwykłe wywołania funkcji. W przeciwieństwie do szablonów HTML, JSX pozwala budować interfejsy jako drzewo wartości i kompozycję funkcji, a nie jako tekst. Dzięki temu powstaje spójny model tworzenia UI, w którym logika, dane i struktura mogą współistnieć bez klejenia wieloma językami i warstwami. Wpis w słowniku wyjaśnia, czym jest JSX z punktu widzenia definicji, jakie ma cechy, na czym polega jego transformacja do zwykłego JS, jak odróżnia się od HTML/XMLa, z jakimi narzędziami współpracuje oraz jakie są praktyczne konsekwencje dla programistów budujących aplikacje webowe.
Definicja i kontekst użycia
JSX to składnia umożliwiająca zapis interfejsu użytkownika jako drzewa wyrażeń. W wymiarze formalnym nie jest językiem szablonów, lecz notacją zapisu obiektów/wywołań funkcji w JavaScript. Każdy fragment JSX-u po kompilacji staje się wywołaniem funkcji lub konstrukcją wytwarzającą strukturę danych reprezentującą wirtualny lub abstrakcyjny model drzewa UI, który następnie może zostać zmaterializowany w przeglądarce, na serwerze lub innym środowisku. W obrębie ekosystemu front-endowego JSX pojawił się jako wygodna alternatywa dla łączenia czystego JS z manipulacjami DOM, oferując jeden spójny paradygmat: UI jako funkcja danych.
Historycznie JSX został spopularyzowany w 2013–2014 roku, gdy pojawił się jako rekomendowany sposób opisu widoków w bibliotece React. Z perspektywy definicyjnej istotne są trzy filary: po pierwsze, JSX to wyrażenia (a nie łańcuchy) – dzięki temu można je składać, przekazywać, zwracać z funkcji i przypisywać do zmiennych. Po drugie, JSX nie wymaga żadnego specyficznego środowiska uruchomieniowego; potrzebny jest jedynie proces transformacji do zwykłego JS. Po trzecie, JSX wprowadza spójne reguły mapowania atrybutów i dzieci elementów, które pozwalają budować komponenty odseparowane i wielokrotnego użytku.
Warto też podkreślić, że choć JSX kojarzy się z virtual DOM-em, to nie jest z nim nierozerwalnie związany. Niektóre biblioteki budują na JSX kompilację do wywołań funkcji, które bezpośrednio modyfikują DOM lub generują statyczny HTML na serwerze. W takim scenariuszu JSX jest wyłącznie wygodnym zapisem deklaratywnym, a to, co z nim zrobi biblioteka, zależy od konfiguracji i docelowego środowiska.
Składnia, reguły i mentalny model
Podstawowy element JSX wygląda podobnie do znacznika HTML: ma nazwę, atrybuty oraz dzieci. Różnica polega na tym, że atrybuty mogą przyjmować wartości dowolnych wyrażeń JS ujętych w klamry. Zamiast literalnych łańcuchów często wykorzystuje się zmienne, wywołania funkcji, operatory warunkowe czy wyrażenia logiczne. Jeśli potrzebna jest wartość tekstowa, można użyć literału łańcuchowego bez klamer; jeśli wartość powinna wynikać z obliczeń – stosuje się klamry. Przykładowo: <Button disabled={isLoading}> wyłącza przycisk w zależności od zmiennej isLoading, a <List items={data.filter(…)} /> przekazuje wynik filtrowania.
Semantyka dzieci w JSX jest prosta: wszystko, co znajduje się między otwierającym i zamykającym znakiem elementu, jest przekazywane jako lista dzieci. Dziećmi mogą być teksty, inne elementy, a także zbiory (np. wynik funkcji map), pod warunkiem że finalnie będą to wartości akceptowalne przez daną bibliotekę renderującą. Najczęściej null, undefined i false są pomijane, bo odpowiadają “brakowi dziecka”. Dzięki temu można zgrabnie realizować warunkowe wstawianie elementów poprzez operator logiczny (warunek && element) lub operator trójargumentowy (warunek ? A : B).
Istotną cechą JSX są nazwy elementów. Nazwy rozpoczynające się małą literą interpretowane są jako elementy wbudowane (np. div, span, svg). Nazwy rozpoczynające się wielką literą są traktowane jako odwołania do zmiennych reprezentujących funkcje lub klasy – to właśnie tak rozpoznaje się komponenty użytkownika. W konsekwencji <profile-card /> będzie rozumiane jako “niższy” element (z mapowaniem do konkretnego środowiska), a <ProfileCard /> jako odwołanie do komponentu ProfileCard.
Składnia JSX zawiera kilka reguł, które odróżniają ją od HTML-a: część nazw atrybutów jest inna (np. className zamiast class, htmlFor zamiast for), nazwy zdarzeń stosują camelCase (onClick, onInput), a style przekazywane są jako obiekt (np. style={{ color: 'red’ }}). Domknięcie elementów bez dzieci może przyjąć postać samozamykającą: <img />, <input /> lub <MyWidget />. Do grupowania dzieci bez dodatkowego opakowującego elementu służą fragmenty: <>…</> lub explicite <Fragment>…</Fragment> zależnie od używanej biblioteki i konfiguracji.
W JSX komentarze wewnątrz wyrażenia wymagają klamer: {/* komentarz */}. Z kolei rozsmarowywanie właściwości obiektu na atrybuty odbywa się przez operator spread: <Widget {…config} />, co ułatwia przekazywanie wielu danych bez wymieniania ich po kolei. Praktyka sugeruje jednak umiar – zbyt szerokie rozsmarowywanie utrudnia zrozumienie API komponentu i jego kontraktu.
Różnice między JSX a HTML (oraz XML)
Mimo podobieństw JSX nie jest HTML-em. Najważniejsze różnice są konsekwencją faktu, że JSX to JavaScript: wartości atrybutów to wyrażenia, a nie łańcuchy znaków; nazwy atrybutów muszą pasować do mapowania właściwości DOM (className, htmlFor); nazewnictwo atrybutów jest czułe na wielkość liter i preferuje camelCase dla zdarzeń i elementów bibliotek. Nie ma bezpośredniej konstrukcji if/for w treści JSX – do sterowania przepływem wykorzystuje się wyrażenia (map, filter, operator warunkowy), a nie instrukcje.
Inną różnicą jest sposób traktowania przestrzeni nazw i atrybutów SVG. Współczesne przekształcenia JSX dbają o poprawne odwzorowanie atrybutów SVG (np. viewBox) i zachowanie zgodności z właściwościami DOM. W starszych konfiguracjach można było napotkać wyjątki lub wymagane dopasowania; dziś narzędzia dokonują odpowiednich translacji bez ingerencji programisty. Również atrybuty aria-* czy data-* są używane w JSX bez zmian, choć sprawdza się poprawność ich zapisów i zgodność z wymogami dostępności.
JSX nie jest też XML-em: co prawda wymusza poprawną domkniętą strukturę (jedno nadrzędne korzenie drzewka-wyrażenia), ale reguły dotyczące białych znaków, normalizacji wartości czy encji różnią się od typowego XML-a. JSX to przede wszystkim składnia języka programowania, a nie samodzielny format dokumentu. Z tego wynika ważna konsekwencja: wszystko, co trafia do JSX, musi finalnie być poprawnym wyrażeniem JS. Tekst wstawiany bezpośrednio między znacznikami staje się łańcuchem znaków; wartości ujęte w klamry są obliczane.
Na poziomie semantyki bezpieczeństwa JSX domyślnie ucieka (escape) wartości wstawiane jako tekst, co ogranicza ryzyko wstrzyknięć HTML (XSS). Gdy potrzebna jest bezpośrednia interpretacja HTML, biblioteki proponują świadome, oznaczone interfejsy (np. dangerouslySetInnerHTML) wraz z odpowiedzialnością po stronie programisty. Ta różnica w praktyce odróżnia JSX od wielu języków szablonów – sabotuje automatyczne wstrzyknięcia, ale wymaga uwagi tam, gdzie intencjonalnie renderuje się surowy HTML.
Od JSX do JavaScriptu: transformacje, narzędzia i ekosystem
JSX nie jest rozumiany natywnie przez przeglądarki; wymaga kroku transformacji. Realizuje go transpiler, który przepisuje zapis znacznikowy na wywołania funkcji lub konstrukcje wytwarzające strukturę danych. Klasycznie było to React.createElement, dziś powszechne są tryby “automatic runtime”, gdzie JSX kompiluje się do importowanych helperów minimalizujących nadmiarowy kod. Krok ten, określany często jako kompilacja, wykonuje zazwyczaj Babel, SWC lub esbuild – bezinteresownie dla programisty w ramach łańcucha narzędzi (Vite, Next.js, Remix, Parcel, Webpack i inne).
W praktyce konfiguracja bywa prosta: włączenie obsługi JSX w pliku konfiguracyjnym narzędzia i ewentualne określenie runtime’u (classic/automatic) oraz źródła importu (jsxImportSource) dla bibliotek alternatywnych wobec Reacta. Gdy używa się TypeScriptu, rozszerzenie plików .tsx pozwala łączyć moderne typowanie z JSX, a kompilacja odbywa się via Babel/SWC z wsparciem dla TS lub przez sam TypeScript, który usuwa adnotacje typów i pozostawia transformację JSX innemu narzędziu. Nowoczesne bundlery dbają o optymalizacje: wstrzykują minimalne helpery, tree-shakują nieużywany kod i generują mapy źródeł.
Tryb produkcyjny i deweloperski mogą różnić się szczegółami transformacji: w deweloperskim dołączane są diagnostyki i nazwy komponentów, a w produkcyjnym – usuwane komentarze i wstawiane drobne optymalizacje. W zależności od biblioteki, docelowe wywołania mogą reprezentować różne modele: wirtualny DOM, bezpośrednie operacje na DOM, generowanie stringów HTML na serwerze lub tworzenie struktur pośrednich do dalszej obróbki (np. streaming SSR).
Ekosystem wokół JSX obejmuje linters i formatery (ESLint, Prettier), które rozumieją składnię i potrafią wymuszać konwencje – np. zakaz nieużywanych zmiennych, preferowanie krótkiej składni fragmentów, kontrolę porządku atrybutów i stylów. Równie ważne są narzędzia testowe – od testów jednostkowych komponentów po testy integracyjne z narzędziami symulującymi DOM, które operują na strukturach powstałych z JSX-u.
Komponenty i przepływ danych w praktyce
Kluczowym zastosowaniem JSX jest deklaratywne budowanie interfejsów za pomocą komponentów funkcjonalnych i klasowych (w nowoczesnym kodzie niemal wyłącznie funkcjonalnych). Komponent to funkcja przyjmująca dane i zwracająca drzewo JSX. Taki komponent może wewnętrznie zarządzać stanem, subskrypcjami, efektami ubocznymi lub pozostawać czystą funkcją – w zależności od wykorzystywanej biblioteki. Kompozycja komponentów umożliwia budowanie większych fragmentów UI z mniejszych, co sprzyja separacji odpowiedzialności, testowalności i reużywalności.
Wejściem do komponentu są zazwyczaj props, czyli obiekt danych przekazywany z rodzica do dziecka. Dzieci elementu trafiają do komponentu jako specjalna właściwość children, dzięki czemu komponenty mogą pełnić rolę kontenerów lub dostawców struktur. Logika warunkowa i iteracyjna realizowana jest na poziomie JS (if w kodzie funkcji, map dla kolekcji, wyrażenia logiczne w klamrach), a wynik to drzewa elementów. W tym ujęciu renderowanie jest funkcją danych: te same wejścia dają te same wyjścia, co czyni UI przewidywalnym i łatwym do testowania.
Obsługa zdarzeń odzwierciedla model DOM, ale jest ujednolicona przez bibliotekę. Nazwy zdarzeń stosują camelCase, a wartości to funkcje – np. onClick={handleClick}. W komponentach formularzy popularny jest model kontrolowany, w którym wartości pól pochodzą ze stanu, a zdarzenia aktualizują ten stan. Modele niekontrolowane delegują przechowywanie wartości do samego DOM-u, a komponent pobiera je przez referencje. Wybór zależy od potrzeb i złożoności.
Listy elementów wymagają stabilnych kluczy (key) dla każdego dziecka na tym samym poziomie, aby biblioteka potrafiła trafnie dopasowywać elementy między aktualizacjami i unikać niepotrzebnego odtwarzania węzłów. Wybranie klucza to kwestia identyfikacji elementu w zbiorze – indeks tablicy zwykle jest złym wyborem, jeśli lista się dynamicznie zmienia. Stabilny identyfikator domenowy minimalizuje artefakty aktualizacji i poprawia ergonomię.
W praktyce z JSX współgra wiele wzorców: render props (przekazywanie funkcji jako dzieci do kształtowania UI), kompozycja kontenerów, przekazywanie kontekstu (Context) do głębszych warstw oraz lazy loading z kodem dzielonym po granicach komponentów. JSX nie ogranicza tych wzorców; jest wygodnym nośnikiem, który łączy składnię deklaratywną z siłą ekspresji JS.
Zaawansowane zastosowania i integracje
JSX świetnie odnajduje się w środowiskach serwerowych i hybrydowych. Renderowanie po stronie serwera (SSR) pozwala generować HTML w momencie żądania, a statyczne generowanie (SSG) tworzy pliki HTML w czasie budowania. W obu przypadkach JSX jest standardowym sposobem wyrażenia widoków, które zostają przekształcone do HTML-a przez bibliotekę i jej narzędzia. Coraz popularniejsze jest strumieniowe SSR (streaming), gdzie komponenty emitują części odpowiedzi w miarę dostępności danych – z punktu widzenia autora kodu JSX pozostaje taki sam, choć pod spodem działa inny model wykonania.
Hydratacja to kolejny etap: gotowy HTML zostaje po stronie klienta powiązany z logiką interaktywną, aby interfejs był żywy i reagował na zdarzenia. Tutaj również JSX jest wyjściową formą zapisu struktury. Nowe paradygmaty, takie jak komponenty serwerowe, wysuwają więcej logiki na serwer, zostawiając klientowi tylko część interaktywną – znów bez zmiany w samej składni JSX.
JSX współistnieje z TypeScriptem jako TSX, dzięki czemu można typować właściwości komponentów, obiekty stylów, zdarzenia i referencje. To ułatwia utrzymanie dużych baz kodu i wzmacnia kontrakty między komponentami. Narzędzia, takie jak ESLint i Prettier, egzekwują konsekwentny styl, a IDE zapewniają podpowiedzi i refaktoryzacje oparte o typy.
W ekosystemie powstały rozwiązania korzystające z JSX w nieoczywistych kontekstach: MDX łączy markdown i JSX, pozwalając mieszać content i komponenty; biblioteki animacji integrują się z JSX przez dedykowane atrybuty i komponenty; systemy projektowe (design systems) dostarczają spójnych zestawów prymitywów budowanych jako komponenty, które w JSX komponuje się jak klocki. W wielu narzędziach konfiguracyjnych można używać JSX do deklarowania widoków podglądów, przykładów i testów wizualnych.
Wydajność, bezpieczeństwo i dobre praktyki
Jak każdy poziom abstrakcji, JSX niesie konsekwencje dla wydajność. Z perspektywy programisty ważne jest unikanie zbędnych tworzeń nowych obiektów i funkcji w środku wyrażeń JSX, gdy powodują one odświeżenia dzieci lub porównywanie zmieniających się referencji. Warto wyciągać stałe poza komponent, memoizować kosztowne obliczenia i rozważać memoizację komponentów w miejscach o dużej częstotliwości aktualizacji. Stabilne klucze w listach, ostrożne dzielenie kodu i unikanie wielkich, monolitycznych drzew to kolejne elementy wpływające na czas aktualizacji UI.
Z punktu widzenia bezpieczeństwo kluczowe znaczenie ma domyślne uciekanie wartości tekstowych: wstawiane dane nie interpretują się automatycznie jako HTML, co minimalizuje ryzyko XSS. Gdy potrzeba wstrzyknąć surowy HTML, biblioteki wymagają użycia świadomych interfejsów – one z kolei obarczają odpowiedzialnością za sanityzację danych. Ochrona przed XSS to nie tylko kwestia pojedynczej funkcji: obejmuje walidację wejść, politykę treści (CSP), ograniczenia inline scriptów i konsekwentną praktykę w całym łańcuchu.
Dobrym zwyczajem jest spójność nazw atrybutów i przejrzyste API komponentów: unikaj nadmiarowych, wieloznacznych właściwości; preferuj kontrakty oparte o jednoznaczne typy i dobrze nazwane parametry. Warto dbać o kolejność atrybutów w JSX (np. najpierw kluczowe jak id, className, potem zdarzenia, a następnie style i pozostałe), co ułatwia przegląd i code review. W projektach z TypeScriptem precyzyjne typowanie propsów pozwala szybko wykryć błędne użycia i niekompatybilności.
Obszar dostępności (a11y) odnosi się do sposobu użycia atrybutów aria-*, roli, etykietowania i semantyki. JSX nie wymusza poprawnej a11y, ale ułatwia jej stosowanie: czytelna kompozycja, komponenty prymitywów dostarczające gotowe wzorce (np. przyciski, przełączniki), a także lintery a11y wykrywające typowe błędy (brak alt na obrazku, niepoprawne skojarzenia label i form controls). Dobrze zaprojektowany komponent opakowuje zawiłości dostępności, tak by użytkownik komponentu w JSX korzystał z prostego API.
Na koniec praktyk warto wspomnieć o stylowaniu: atrybut style przyjmuje obiekt JS odwzorowany na style inline, ale w większych projektach częściej korzysta się z klas (CSS/SCSS), CSS Modules lub rozwiązań CSS-in-JS. JSX nie faworyzuje żadnej opcji – to, jak ostatecznie powstają style, zależy od infrastruktury projektu. Ważne, by nie mnożyć rozwiązań i trzymać się spójnego podejścia.
Perspektywa porównawcza i ewolucja paradygmatu
JSX często porównuje się do tradycyjnych szablonów HTML renderowanych na serwerze lub w przeglądarce. Największą różnicą pozostaje fakt, że JSX jest częścią języka programowania, a nie osobnym DSL-em. Wprowadza to jednolitość – ta sama składnia ogarnia logikę i strukturę widoku; eliminuje potrzebę osobnego systemu szablonów, filtrów i helperów. To też przesuwa odpowiedzialność: zamiast uczyć się osobnych reguł składni szablonów, programista wykorzystuje znane narzędzia JS – typy, funkcje, moduły.
W ekosystemie powstały alternatywy i warianty: niektóre biblioteki wykorzystują JSX, ale kompilują go do wywołań o innej semantyce (np. minimalizacja pracy w czasie aktualizacji poprzez statyczną analizę i finezyjne patchowanie DOM). Inne z kolei promują brak JSX i stosują czysty JS lub tagowane template stringi. Czasem wybór podyktowany jest wydajnością, czasem preferencjami zespołu, a czasem charakterem projektu (duża aplikacja z wieloma stanami vs. prosta strona statyczna).
W miarę ewolucji narzędzi rozwinęły się też runtime’y kompilacji JSX. Tryb automatic ogranicza konieczność jawnych importów i minimalizuje narzut, a jednocześnie lepiej współgra z tree shakingiem. Pojawiły się też mechanizmy do wyłuskiwania statycznych fragmentów JSX, które mogą być renderowane raz i cache’owane, co redukuje obciążenie w czasie działania. Przy odpowiedniej konfiguracji deweloper otrzymuje składnię deklaratywną, która przekłada się na bardzo niskie koszty wykonania – wszystko za sprawą sprytnej kompilacji i transformacji wyrażeń.
Równolegle w świecie dokumentów i contentu JSX stał się standardem de facto w narzędziach do projektowania systemów komponentów, bibliotek UI i stron dokumentacji. Dzięki niemu komponenty i przykłady można osadzić bezpośrednio w treści, a edytory potrafią renderować podgląd na żywo, łącząc tekst, kod i interaktywne elementy. Taki model wzmacnia sprzężenie zwrotne i skraca cykl pracy.
FAQ: najczęstsze pytania o definicję JSX
- Czy JSX to język szablonów? Nie. JSX to składnia wyrażeń JavaScript, która po transformacji staje się wywołaniami funkcji lub strukturami danych. Nie działa bezpośrednio w przeglądarce, wymaga kroku kompilacji/transformacji.
- Czy potrzebuję Reacta, aby używać JSX? Nie. Choć kojarzy się z Reactem, JSX wspierają także inne biblioteki i narzędzia. Wymagany jest odpowiedni runtime kompilacji oraz funkcje, do których JSX zostanie przekształcony.
- Dlaczego w JSX używa się className zamiast class? Ponieważ class jest słowem zarezerwowanym w JS, a JSX mapuje atrybuty na właściwości obiektów. className jest ustaloną konwencją odpowiadającą właściwościom DOM w środowisku przeglądarkowym.
- Jak w JSX wstawia się wartości dynamiczne? Za pomocą klamer: {wyrażenie}. To może być zmienna, wynik funkcji, operator warunkowy, wynik mapowania tablicy itd.
- Czy w JSX można używać instrukcji if lub pętli for? Bezpośrednio w treści JSX – nie. JSX to wyrażenia. Logikę warunkową i iteracje umieszcza się w kodzie JS (np. map) albo stosuje operator warunkowy w klamrach.
- Co się dzieje z JSX podczas budowania? Transpiler przekształca zapis znacznikowy na wywołania funkcji lub konstrukcje tworzące strukturę elementów. W trybie automatic narzędzia dodają importy helperów i optymalizują wynik.
- Jak obsłużyć listy elementów w JSX? Najczęściej poprzez items.map(…) zwracające tablicę elementów. Każde dziecko powinno mieć stabilny key na danym poziomie, aby biblioteka mogła efektywnie dopasować elementy podczas aktualizacji.
- Czy JSX jest bezpieczny pod kątem XSS? Domyślnie wartości tekstowe są “escape’owane”, więc złośliwy HTML nie zostanie wykonany. Surowy HTML wstawia się świadomie przez dedykowane API, co wymaga samodzielnej sanityzacji danych.
- Na czym polega różnica między elementem wbudowanym a komponentem? Wbudowane mają nazwy z małej litery (div, span) i mapują się na prymitywy środowiska (np. DOM). Komponenty zaczynają się od wielkiej litery i odnoszą do funkcji/klas zdefiniowanych w kodzie, które zwracają JSX.
- Czy muszę używać TypeScriptu, aby korzystać z JSX? Nie, JSX działa w czystym JS. TypeScript (TSX) daje jednak korzyści typowania i lepsze doświadczenie w IDE, zwłaszcza w większych projektach.
- Jak stylować elementy w JSX? Możesz użyć style={{…}} jako obiektu JS dla styli inline, przekazać className z klasami CSS, skorzystać z CSS Modules, bibliotek CSS-in-JS lub systemów projektowych – wybór zależy od architektury projektu.
- Dlaczego mówi się, że JSX to “cukier składniowy”? Bo finalny program nie potrzebuje składni znacznikowej do działania. To tylko wygodna notacja, która po transformacji staje się zwykłym kodem JS (wywołania funkcji, obiekty, struktury).
- Czy JSX wpływa na wydajność? Sam zapis nie – decydują implementacja biblioteki i wzorce użycia. Dobre klucze w listach, unikanie zbędnych re-renderów i rozsądne zarządzanie stanem mają większe znaczenie niż sama obecność JSX.
- Czy można używać JSX poza przeglądarką? Tak. JSX bywa renderowany na serwerze (SSR/SSG), w narzędziach dokumentacyjnych, w generatorach stron statycznych, a nawet w środowiskach natywnych poprzez warstwy pośrednie, o ile istnieje runtime interpretujący wynik transformacji.
- Jak dodać komentarz w JSX? Wewnątrz wyrażenia JSX komentarz zapisuje się jako {/* komentarz */}. Poza JSX – zwykłe komentarze JS (// lub /* */).
- Co zrobić, gdy muszę wstawić surowy HTML? Użyć udostępnionego przez bibliotekę API (np. dangerouslySetInnerHTML) i samodzielnie zadbać o oczyszczanie danych. Rozwiązanie to stosuj oszczędnie i świadomie.
- Po co klamry w atrybutach, skoro mogę użyć łańcucha? Łańcuch nadaje się do wartości stałych. Klamry umożliwiają przekazanie wyniku wyrażenia JS (np. zmiennej, funkcji, obliczenia), co pozwala dynamicznie kształtować UI.