Przejdź do treści
Tailwind CSS toggle: jak wdrożyć dostępny przełącznik

Tailwind CSS toggle: jak wdrożyć dostępny przełącznik

Opublikowano: 16 października 2026| Zaktualizowano: 16 października 2026

Przełącznik w filtrze powinien zmieniać widoczne wyniki, a ustawienie użytkownika powinno zachować spójny stan po każdej interakcji. Tailwind CSS ułatwia stylowanie stanów, lecz działanie kontrolki i jej dostępność zależą od HTML oraz logiki aplikacji.

Krótka odpowiedź

Użyj natywnego `

Usługi KC Mobile

Potrzebujesz pomocy w tym temacie?

Czytasz poradnik „Tailwind CSS toggle: jak wdrożyć dostępny przełącznik”. Napisz, co chcesz zrobić i na jakim etapie jesteś. Ustalimy, czy możemy pomóc i jaki zakres prac będzie potrzebny.

Czym różni się toggle od zwykłego przycisku?

Toggle przełącza trwały stan między włączonym i wyłączonym, natomiast zwykły przycisk uruchamia jednorazową akcję, taką jak wysłanie formularza lub otwarcie okna. Przycisk "Dostępne od ręki" może aktywować filtr, a "Zapisz" wykonuje akcję i nie powinien pozostawać wciśnięty.

W filtrach kilka toggle może być aktywnych równocześnie, na przykład "Dostępne od ręki" oraz "Promocja". Gdy użytkownik ma wybrać jedną z opcji, takich jak widok listy albo siatki, rozważ pojedynczą grupę wyboru z właściwą semantyką zamiast niezależnych przycisków toggle.

Dla przycisku przełączającego zachowaj stałą nazwę, a stan podawaj przez `aria-pressed`. Przykładowo nazwa "Wycisz" może pozostać niezmieniona, gdy wartość `aria-pressed` przechodzi z `false` na `true`. Jeśli zmieniasz nazwę z "Wycisz" na "Włącz dźwięk", zwykle komunikujesz stan już tekstem i trzeba rozważyć zwykłą akcję zamiast przycisku toggle.

Czytasz poradnik „Tailwind CSS toggle: jak wdrożyć dostępny przełącznik”. Napisz, co chcesz zrobić i na jakim etapie jesteś. Ustalimy, czy możemy pomóc i jaki zakres prac będzie potrzebny. Omów temat tego poradnika

Jak przygotować strukturę przycisku w Tailwind CSS?

Zacznij od semantycznego `

Jak przełączać stan i zmieniać wygląd?

Obsługa kliknięcia powinna w jednym miejscu zaktualizować stan kontrolki i wykonać jej właściwe działanie. W tym przykładzie JavaScript filtruje elementy oznaczone `data-available`, zmieniając ich właściwość `hidden`.

<button
  id="availability-toggle"
  type="button"
  aria-pressed="false"
  class="rounded-md border px-4 py-2 aria-pressed:bg-violet-700 aria-pressed:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-700"
>
  Dostępne od ręki
</button>
<p id="results-count" aria-live="polite" aria-atomic="true"></p>
<ul>
  <li data-available="true">Produkt dostępny</li>
  <li data-available="false">Produkt na zamówienie</li>
</ul>

<script>
  const toggle = document.querySelector("#availability-toggle");
  const products = [...document.querySelectorAll("[data-available]")];
  const count = document.querySelector("#results-count");

  function updateResults(isPressed) {
    let visibleCount = 0;

    products.forEach((product) => {
      const visible = !isPressed || product.dataset.available === "true";
      product.hidden = !visible;
      if (visible) visibleCount += 1;
    });

    count.textContent = `Liczba produktów: ${visibleCount}.`;
  }

  toggle.addEventListener("click", () => {
    const nextState = toggle.getAttribute("aria-pressed") !== "true";
    toggle.setAttribute("aria-pressed", String(nextState));
    updateResults(nextState);
  });
</script>

Region `aria-live="polite"` ogłasza zmianę liczby wyników, ponieważ sam `aria-pressed` informuje tylko o stanie kontrolki. Komunikat nie powinien odczytywać każdej pozycji listy; przekazuje zmianę, która pomaga zrozumieć efekt filtra. Przy dużej liście możesz uruchomić zapytanie do API zamiast ukrywać istniejące elementy, ale obsłuż także stan ładowania i błąd odpowiedzi.

Jeśli źródłem listy jest serwer, zaktualizuj wyniki dopiero zgodnie z ustalonym zachowaniem żądania. Nie pozostawiaj aktywnego wizualnie przełącznika, gdy żądanie zakończyło się błędem i filtr nie zadziałał. W aplikacji frameworkowej stan powinien należeć do tego frameworka, a DOM ma z niego wynikać.

Schemat wyjaśnia przepływ od zmiany stanu przycisku przez filtrowanie listy i liczenie wyników po ogłoszenie efektu.

Który wariant wdrożenia wybrać?

Wybierz technologię, która już zarządza stanem danego widoku. Pojedynczy toggle nie uzasadnia dodania frameworka do strony, ale powielona logika w kilku miejscach może uzasadniać wspólny komponent.

Porównanie sposobów wdrożenia przełącznika, zależności i zakresu utrzymania
WariantZależnościKiedy pasujeCo utrzymywać
HTML i JavaScriptBez frameworkaJeden filtr albo ustawienie w małym widokuObsługę zdarzenia, stan i aktualizację wyników
Alpine.jsAlpine.js obecny na stronieLekka interakcja w komponencie HTMLStan w `x-data` i powiązanie go z atrybutem oraz widokiem
ReactInterfejs lub wyspa ReactStan listy i filtrów już należy do komponentów ReactStan React, komponent oraz przekazanie wyników

Przykład Alpine.js używa `x-data` do przechowania stanu, a `@click` do jego zmiany. Atrybut `:aria-pressed` i licznik wyników odczytują tę samą wartość:

<div x-data="{ active: false, count: 12 }">
  <button type="button" :aria-pressed="active.toString()" @click="active = !active; count = active ? 4 : 12"
          class="rounded-md border px-4 py-2 aria-pressed:bg-violet-700 aria-pressed:text-white focus-visible:outline-2 focus-visible:outline-offset-2">
    Dostępne od ręki
  </button>
  <p aria-live="polite" x-text="`Liczba produktów: ${count}.`"></p>
</div>

Przykład React przechowuje stan w `useState` i renderuje z niego zarówno atrybut, jak i tekst licznika:

import { useState } from "react";

function AvailabilityToggle() {
  const [active, setActive] = useState(false);
  const count = active ? 4 : 12;

  return (
    <div>
      <button
        type="button"
        aria-pressed={active}
        onClick={() => setActive((value) => !value)}
        className="rounded-md border px-4 py-2 aria-pressed:bg-violet-700 aria-pressed:text-white focus-visible:outline-2 focus-visible:outline-offset-2"
      >
        Dostępne od ręki
      </button>
      <p aria-live="polite" aria-atomic="true">Liczba produktów: {count}.</p>
    </div>
  );
}

W przykładach licznik jest uproszczony; w produkcyjnym filtrze obliczaj go z faktycznie wyświetlanej listy. Alpine wiąże zdarzenia przez `x-on` lub skrót `@` w zasięgu `x-data`; React renderuje aktualizację z własnego stanu komponentu. Zobacz dokumentacje Alpine.js i stanu komponentu React, aby dopasować kod do aplikacji.

Jak obsłużyć fokus, klawiaturę i czytniki ekranu?

Natywny przycisk zapewnia obsługę klawiatury bez własnych handlerów `keydown`. Tab przenosi fokus, a Enter i Spacja aktywują kontrolkę; dodatkowe ręczne wywoływanie kliknięcia dla tych klawiszy może spowodować podwójne działanie.

Pozostaw widoczny fokus podczas nawigacji klawiaturą. `focus-visible:outline-2` tworzy obrys, ale sprawdź jego kontrast na tle strony, aktywnego przycisku i sąsiednich elementów. Nie usuwaj wskaźnika klasą `outline-none`, jeśli nie zastępujesz go równie widocznym oznaczeniem.

Czytnik ekranu odczytuje nazwę przycisku oraz stan `aria-pressed`. Przy toggle utrzymaj tę samą nazwę dla obu stanów, aby użytkownik rozumiał, że przełączył funkcję. Gdy aktywacja prowadzi do nowego kontekstu, na przykład otwiera dialog, zastosuj zasady fokusu właściwe dla tego wzorca zamiast traktować go jak filtr.

Dla filtrów liczba wyników to osobna informacja. Zaktualizuj region `aria-live="polite"` po przeliczeniu listy i podaj krótką zmianę, taką jak "Liczba produktów: 4". Gdy wynik jest aktualizowany przy każdym kliknięciu kilku filtrów, aktualizuj jeden region z końcową liczbą, a nie wiele komunikatów opisujących pośrednie etapy.

Jak uniknąć typowych błędów w toggle button?

Błędy powstają, gdy styl komponentu i funkcja aplikacji mają niezależne stany. Tabela pomaga znaleźć, czy problem dotyczy HTML, logiki, czy komunikowania wyniku.

Błędy przełączników, ich skutki i zalecane poprawki dostępności
BłądSkutekPoprawka
Zmienia się kolor, ale nie `aria-pressed`Czytnik ekranu otrzymuje nieaktualny stanAktualizuj atrybut z tego samego źródła stanu co wygląd
Zmienia się `aria-pressed`, ale lista pozostaje bez zmianKontrolka sygnalizuje efekt, którego użytkownik nie widziPowiąż stan z filtrem i ogłoś nową liczbę wyników
Elementem jest `div` albo link bez nawigacjiBrakuje oczekiwanej semantyki i obsługi klawiaturyZastosuj natywny `
Fokus znika po użyciu `outline-none`Użytkownik klawiatury traci informację o położeniuZapewnij i sprawdź widoczny obrys fokusu
Etykieta zmienia się równocześnie z `aria-pressed`Nazwa może dublować albo zaciemniać stanZachowaj nazwę toggle lub wybierz wzorzec zwykłej akcji
Filtr zmienia listę bez komunikatu o liczbie wynikówUżytkownik czytnika może nie zauważyć efektuAktualizuj jeden spokojny region live po zmianie listy

Perspektywa KC Mobile: przy filtrach sprawdzamy efekt w danych i licznikach obok samego kliknięcia. Typowy problem to przycisk, który zmienia kolor, podczas gdy lista nie reaguje, bo kontrolka nie jest połączona z logiką widoku. Jeśli filtr ma być zapamiętany, sprawdzamy też zachowanie po ponownym załadowaniu strony.

Jak sprawdzić przełącznik przed publikacją?

Przetestuj kontrolkę na telefonie i komputerze, a następnie sprawdź efekty interakcji poza samym przyciskiem. Wąski ekran może zmienić układ filtrów, a prawidłowy `aria-pressed` nie dowodzi jeszcze, że lista zmieniła się zgodnie z oczekiwaniem.

Testy przełącznika, działania użytkownika i oczekiwane wyniki
TestDziałanieOczekiwany wynik
Stan początkowyOtwórz stronę i sprawdź filtrWygląd, `aria-pressed` i widok odpowiadają sobie
Aktywacja i ponowna aktywacjaKliknij, a potem wyłącz filtrStan przechodzi w obie strony, wyniki aktualizują się
KlawiaturaPrzejdź Tabem i aktywuj Enterem oraz SpacjąFokus jest widoczny, każde użycie powoduje pojedynczą zmianę
Czytnik ekranuOdczytaj przycisk i zmień filtrNazwa jest zrozumiała, stan i liczba wyników są ogłoszone
Zmiana szerokościSprawdź szeroki i wąski widokEtykieta, fokus i kontrolka pozostają widoczne
Współdziałanie filtrówWłącz dwa filtry, zmień sortowanie i wyczyść filtryLista i licznik odpowiadają aktywnym ustawieniom

W narzędziach deweloperskich przeglądarki obserwuj `aria-pressed` w panelu Elements. Dla przykładowego elementu możesz odczytać wartość w konsoli: `document.querySelector("#availability-toggle").getAttribute("aria-pressed")`. Testuj także wynik listy i treść regionu na żywo, ponieważ atrybut przycisku sam nie potwierdza działania filtra.

Sprawdź, czy kompilator Tailwind nie usunął klas użytych w komponentach generowanych dynamicznie. Jeśli składasz nazwę klasy z fragmentów tekstu, na przykład `aria-pressed:bg-` oraz zmiennego koloru, skaner może nie wykryć pełnej klasy; użyj pełnych nazw klas albo skonfiguruj źródła skanowania zgodnie z wersją Tailwind. Gdy projekt ma wspólny system komponentów, wdrożenie Tailwind CSS może objąć dopasowanie wariantów, logiki oraz testów do istniejącego stosu.

Lista kontrolna pokazuje, jak sprawdzić stany toggle, obsługę klawiaturą i czytnikiem, widoczność oraz współdziałanie filtrów.

Więcej poradników w tym temacie

Wspomniane narzędzia

Tailwind CSSJavaScriptAlpine.jsReactWAI-ARIAprzeglądarkowe narzędzia deweloperskie

Najczęściej zadawane pytania

Jak zrobić toggle button w Tailwind CSS?
Użyj `
Czy Tailwind CSS ma gotowy komponent toggle?
Tailwind CSS udostępnia klasy narzędziowe i warianty stanów, ale nie dostarcza gotowej logiki komponentu toggle. HTML, obsługę interakcji, źródło stanu i połączenie z filtrem przygotowuje projekt.
Jak zmienić kolor aktywnego przycisku toggle w Tailwind CSS?
Dodaj na przycisku klasy, takie jak `aria-pressed:bg-violet-700` i `aria-pressed:text-white`. Wariant `aria-pressed:*` jest wbudowany od Tailwind CSS 3.2; w starszej wersji użyj selektora CSS lub skonfiguruj wariant.
Jak dodać aria-pressed do przycisku Tailwind?
Umieść `aria-pressed="false"` na elemencie `
Czy do przełącznika Tailwind CSS potrzebuję JavaScriptu?
Tak, jeśli kliknięcie ma zmieniać filtr, ustawienie albo widok. Tailwind odpowiada za prezentację, a JavaScript, Alpine.js lub React utrzymuje stan i uruchamia odpowiednie działanie.
#Tailwind CSS#toggle button#przycisk przełączający#dostępność WCAG#aria-pressed#JavaScript#React#Alpine.js
Zdjęcie autora: Krzysztof Czapnik
O autorze

Krzysztof Czapnik

Founder & Technical Lead, KC Mobile

Projektuję i rozwijam strony WordPress, sklepy WooCommerce oraz aplikacje internetowe. Łączę projektowanie z programowaniem, integracjami i technicznym SEO. Projekty KC Mobile prowadzę osobiście.

Potrzebujesz pomocy z tym tematem? Napisz - odpowiem osobiście w 24h.

Potrzebujesz pomocy w tym temacie?

Czytasz poradnik „Tailwind CSS toggle: jak wdrożyć dostępny przełącznik”. Napisz, co chcesz zrobić i na jakim etapie jesteś. Ustalimy, czy możemy pomóc i jaki zakres prac będzie potrzebny.