shadcn/ui, kod w repozytorium i zmiana na Base UI
shadcn/ui bywa opisywane jako biblioteka komponentów i to jest największe nieporozumienie wokół niego. To nie jest zależność, którą instalujesz i aktualizujesz. To jest sposób dystrybucji kodu: uruchamiasz polecenie, a ono kopiuje pliki komponentów do Twojego repozytorium, gdzie stają się Twoim kodem.
Ta różnica wygląda na szczegół i tłumaczy praktycznie wszystko, co dzieje się z tym projektem, łącznie z najważniejszą zmianą z lipca 2026 roku.
Zmiana fundamentu na Base UI
Komponenty potrzebują warstwy spodniej: mechanizmów obsługujących ogniskowanie, nawigację klawiaturą, warstwy nakładkowe i dostępność. Przez lata tę rolę pełnił Radix.
Od lipca 2026 nowe projekty startują domyślnie na Base UI, bibliotece rozwijanej przez zespół stojący za MUI, która osiągnęła pierwszą stabilną wersję w grudniu 2025 roku. Dokumentacja prowadzi teraz przez Base UI, a wariant oparty o Radix jest jedno kliknięcie dalej.
Rzecz najważniejsza dla osób z działającym projektem: Radix pozostaje w pełni wspierany, a projekty na nim oparte nie muszą migrować. To nie jest wygaszanie, tylko zmiana wartości domyślnej.
I tu wracamy do pierwszego akapitu. Ta zmiana była możliwa bez zepsucia czegokolwiek właśnie dlatego, że komponenty leżą w repozytoriach użytkowników. Nie ma pakietu, który podniósłby wersję główną i zmusił wszystkich do migracji. Nowe projekty dostają nowy fundament, stare zostają przy swoim, a jedno i drugie działa.
Dla osób, które chcą przejść, przygotowano nie polecenie w wierszu poleceń, tylko umiejętność dla agenta kodującego: instalujesz opis różnic między obiema bibliotekami, a potem prosisz agenta o przeniesienie konkretnego komponentu. Autorzy tłumaczą ten wybór wprost: przekształcenie automatyczne poradziłoby sobie z plikami nietkniętymi, a wywróciłoby się na tych, które sam zmieniałeś. Działa to stopniowo: przenosisz jeden komponent i miejsca jego użycia, projekt cały czas się buduje, obie biblioteki współistnieją w trakcie. To jest właściwe podejście, bo migracja jednym ruchem przy dwudziestu komponentach jest ryzykowna.
Wcześniejsza zmiana, o której warto wiedzieć
W lutym 2026 roku komponenty generowane przez to narzędzie przeszły na zbiorczy pakiet Radiksa. Wcześniej każdy komponent importował z osobnego pakietu przypisanego do niego, dziś importuje ze wspólnego. Warto tu być precyzyjnym: to jest zmiana importów w generowanym kodzie, a nie wycofanie czegokolwiek. Pakiety przypisane do pojedynczych komponentów nadal są wydawane i nie są oznaczone jako przestarzałe, a zbiorczy pakiet istnieje od początku 2025 roku.
Praktyczna konsekwencja dotyczy projektów, które nie aktualizowały się od dłuższego czasu. Import z pakietu przypisanego do pojedynczego komponentu nadal działa, natomiast przy dokładaniu nowych komponentów warto ujednolicić importy, bo mieszanie dwóch sposobów w jednym projekcie potrafi wciągnąć dwie wersje tej samej rzeczy. Do samego ujednolicenia jest osobne polecenie migrujące importy, i to akurat jest polecenie, a nie praca dla agenta.
To jest zresztą charakterystyczne dla tego projektu: zmiany są częste, a materiały w sieci starzeją się w kilka miesięcy. Data przy poradniku ma tu większe znaczenie niż przy większości bibliotek.
Dlaczego kopiowanie kodu ma sens
Warto uzasadnić to podejście, bo brzmi jak krok wstecz wobec zwykłej zależności.
Zwykła biblioteka komponentów daje wygodę na starcie i ścianę później. Dopóki komponent robi to, czego chcesz, wszystko jest w porządku. Gdy potrzebujesz zmienić coś, czego autor nie przewidział, zaczynasz nadpisywać style, walczyć z selektorami i szukać obejść.
Tutaj tej ściany nie ma, bo komponent jest Twoim plikiem. Zmieniasz go jak każdy inny kod w projekcie, bez proszenia nikogo o zgodę i bez czekania na nową wersję.
Cena jest równie konkretna. Nie dostajesz aktualizacji. Poprawka błędu wprowadzona w źródle nie dotrze do Ciebie sama, więc albo śledzisz zmiany i przenosisz je ręcznie, albo żyjesz z wersją, którą skopiowałeś. Przy dwudziestu komponentach to jest realna praca.
Praktyczna reguła wychodzi po kilku projektach. Kopiuj komponenty, które będziesz zmieniał, a przy tych, których zmieniać nie zamierzasz, rozważ zwykłą zależność. Przycisk i pole tekstowe prawie zawsze się przerabia, więc pasują tutaj. Złożony wykres albo edytor tekstu sformatowanego rzadziej, więc tam biblioteka bywa lepsza.
Jak to działa w praktyce
pnpm dlx shadcn@latest init
pnpm dlx shadcn@latest add button dialog formPierwsze polecenie ustawia projekt: konfigurację Tailwinda, zmienne kolorów, pomocnicze funkcje i ścieżki. Drugie kopiuje wskazane komponenty do katalogu, który sam wskazałeś.
Od tego momentu pliki są Twoje. Zmiana wariantu przycisku to edycja pliku, a nie szukanie właściwości w dokumentacji.
Warto zwrócić uwagę na jedną rzecz przy pierwszym uruchomieniu. Polecenie inicjujące zadaje pytania o strukturę projektu i zapisuje odpowiedzi do pliku konfiguracyjnego.
{
"$schema": "https://ui.shadcn.com/schema.json",
"tsx": true,
"tailwind": {
"css": "src/app/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"ui": "@/components/ui",
"utils": "@/lib/utils"
}
}Ten plik decyduje potem, gdzie trafiają kolejne komponenty, więc warto go przejrzeć, zamiast klikać przez pytania. Szczególnie wpis o zmiennych kolorów: przestawienie go później oznacza przepisanie wszystkiego, co zdążyło powstać.
Przy nowym projekcie dochodzi wybór fundamentu. Narzędzie przyjmuje przełącznik wskazujący bibliotekę mechanizmów, więc decyzja jest jawna, a nie ukryta w wartości domyślnej. Wartości są trzy, nie dwie: obok Base UI i Radiksa doszła w lipcu 2026 roku React Aria, traktowana odtąd na równi z pozostałymi, z własną dokumentacją i własnym rejestrem.
Motyw i zmienne kolorów
Warstwa wizualna opiera się tu na zmiennych, a nie na klasach wpisanych wprost w komponenty, i to jest decyzja o większych konsekwencjach, niż wygląda.
Kolory są opisane jako zmienne o nazwach mówiących o roli, a nie o barwie. Komponent nie wie, że przycisk jest niebieski, wie tylko, że używa koloru podstawowego.
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--destructive: oklch(0.577 0.245 27.325);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
}Nazwy występują parami: kolor tła i kolor tekstu, który na nim wystarczająco kontrastuje. To rozwiązuje problem, o którym łatwo zapomnieć przy podmianie motywu, bo zmiana samego tła bez zmiany tekstu daje wynik zgodny z zamysłem i nieczytelny.
Zysk widać przy dwóch rzeczach. Tryb ciemny sprowadza się do podmiany wartości zmiennych, a nie do pisania wariantów każdego komponentu. Zmiana kolorystyki całej aplikacji to edycja jednego pliku, a nie przejście przez pięćdziesiąt plików komponentów.
Cena polega na tym, że nazwy ról trzeba przemyśleć na starcie. Zestaw domyślny jest rozsądny i uniwersalny, natomiast produkt z własnym systemem wizualnym zwykle potrzebuje kilku ról dodatkowych, a dokładanie ich po roku oznacza przegląd wszystkiego, co już powstało.
Praktyczna rada: rozszerz zestaw zmiennych zanim skopiujesz dwadzieścia komponentów, a nie po. Dopisanie dwóch ról na początku kosztuje kwadrans, a to samo po pół roku pracy jest osobnym zadaniem.
Warto też trzymać zmienne w jednym miejscu i traktować ten plik jako granicę między systemem wizualnym a kodem. Komponent sięgający po konkretny odcień zamiast po rolę jest wyłomem, który rozejdzie się po projekcie, jeśli nikt go nie zatrzyma przy przeglądzie.
Dostępność i to, czego nie widać
Warto powiedzieć, za co właściwie odpowiada warstwa spodnia, bo to jest główny powód, dla którego w ogóle się jej używa zamiast pisać komponenty od zera.
Okno dialogowe to nie jest element z ramką. To jest pułapka ogniskowania, żeby klawiatura nie wyszła poza okno, obsługa klawisza zamykającego, przywrócenie ogniskowania po zamknięciu, zablokowanie przewijania tła, ogłoszenie zmiany czytnikowi ekranu i zachowanie na urządzeniu dotykowym. Każdą z tych rzeczy da się napisać samodzielnie i każda ma przypadki brzegowe, o których dowiadujesz się z raportu z audytu.
Lista rozwijana jest jeszcze gorsza, bo dochodzi nawigacja strzałkami, wybór przez wpisanie pierwszych liter, zachowanie przy przewijaniu i pozycjonowanie względem krawędzi ekranu.
To jest właśnie ta część, która nie jest widoczna w kodzie skopiowanym do repozytorium, bo mieszka w zależności pod spodem. Zmiana fundamentu z lipca 2026 dotyczyła dokładnie tej warstwy, i dlatego była zauważalna dla nowych projektów, a niewidoczna dla istniejących.
Praktyczny wniosek przy zmienianiu skopiowanych komponentów: styl i układ zmieniaj bez obaw, a przy zachowaniu i atrybutach dostępności zastanów się dwa razy.
<DialogContent className="max-w-2xl gap-8 p-10">
<DialogTitle>Usunac zamowienie</DialogTitle>
<DialogDescription>
Tej operacji nie da sie cofnac.
</DialogDescription>
</DialogContent>Klasy w pierwszej linii to zmiana bezpieczna. Usunięcie znacznika tytułu albo opisu, bo wizualnie są zbędne, już nie: czytnik ekranu traci wtedy jedyną informację o tym, czym jest otwarte okno, a w trybie deweloperskim pojawia się ostrzeżenie, które łatwo zignorować jako hałas.
shadcn/ui kontra alternatywy
| Rozwiązanie | Postać | Aktualizacje | Kiedy wybrać |
|---|---|---|---|
| shadcn/ui | Kod w Twoim repozytorium | Ręcznie, przez ponowne dodanie | Własny system wizualny, potrzeba zmian |
| Radix albo Base UI wprost | Zależność, bez stylów | Automatyczne | Chcesz sam napisać wszystkie style |
| Biblioteka ze stylami | Zależność ze stylami | Automatyczne | Panel wewnętrzny, szybki start |
| Komponenty pisane od zera | Twój kod | Twoje | Bardzo nietypowe wymagania |
Drugi wiersz warto rozważyć, bo bywa pomijany. Jeśli i tak przepiszesz wszystkie style, warstwa pośrednia z gotowym wyglądem niewiele wnosi, a kopiowanie kodu, który zaraz zmienisz, jest okrężną drogą. Sięgnięcie wprost po bibliotekę mechanizmów daje to samo bez pośrednika.
Trzeci wiersz wygrywa tam, gdzie wygląd nie jest wyróżnikiem. Panel administracyjny używany przez dwadzieścia osób nie potrzebuje własnego systemu wizualnego, a gotowa biblioteka ze stylami oszczędza tygodnie.
Pierwszy wiersz jest właściwy wtedy, gdy masz własny system wizualny albo wiesz, że będziesz zmieniał zachowanie komponentów. Wtedy kopiowanie kodu jest zaletą, a nie kompromisem.
Ten sam model kopiowania kodu obrósł zbiorami gotowych elementów, z których warto korzystać wybiórczo. Aceternity UI daje komponenty z efektami 3D i animacjami, Uiverse zbiera społecznościowe elementy w czystym CSS i Tailwindzie. Traktuj je jak katalog inspiracji, a nie zależność: kod trafia do Twojego repozytorium na tych samych zasadach, więc odpowiadasz za jego jakość i dostępność.
Rejestr i własne komponenty
Mechanizm dystrybucji nie jest zamknięty i to jest możliwość, o której mało kto wie.
Rejestr to opis komponentów w ustalonym formacie, dostępny pod adresem. Narzędzie potrafi pobierać z rejestrów innych niż domyślny, więc firma może wystawić własny zestaw i rozdawać go zespołom tym samym poleceniem.
To rozwiązuje realny problem przy większej organizacji. System wizualny wydawany jako paczka wymusza aktualizacje i wersjonowanie, a rozdawany jako kod pozwala każdemu zespołowi dostosować komponent do swojego przypadku, zachowując wspólny punkt wyjścia.
Z tego samego mechanizmu korzystają całe zewnętrzne biblioteki. Najlepszym przykładem jest coss ui, dawne Origin UI, które zrezygnowało z własnego instalatora i publikuje komponenty przez przestrzeń nazw w rejestrze, więc dodaje się je dokładnie tym samym poleceniem co elementy shadcn i na tym samym fundamencie Base UI.
Przy budowaniu własnego rejestru warto wskazać w konfiguracji, na jakiej bibliotece mechanizmów stoją Twoje komponenty. Bez tego zostaną potraktowane jako oparte o wartość domyślną, co po lipcowej zmianie znaczy Base UI, a nie Radix.
Warto też wiedzieć, że narzędzia generujące interfejsy, na przykład v0, wypuszczają kod w tej konwencji. To jest wygodne, bo wynik wpina się w projekt bez tłumaczenia, i warto o tym pamiętać przy ocenie, czy taki generator w ogóle pasuje do Twojego stosu.
Typowe błędy
Pierwszy to traktowanie tego jak zależności i oczekiwanie aktualizacji. Poprawki ze źródła nie docierają same, więc trzeba je przenosić świadomie albo zaakceptować wersję, którą się skopiowało.
Drugi to kopiowanie wszystkich dostępnych komponentów na start. Repozytorium zapełnia się plikami, których nikt nie używa, a przy przeglądzie kodu nie da się odróżnić kodu żywego od skopiowanego na zapas.
Trzeci to uczenie się z materiałów bez sprawdzenia daty. Ten projekt zmieniał fundament i strukturę pakietów w ciągu jednego roku, więc poradnik sprzed roku opisuje inny stan.
Czwarty to migracja wszystkich komponentów naraz. Przeniesienie prowadzone przez agenta działa stopniowo właśnie po to, żeby projekt cały czas się budował, a przejście jednym ruchem odbiera tę zaletę.
Piąty to zmiana skopiowanego komponentu bez zapisania, co i dlaczego zmieniono. Przy ponownym dodaniu tego samego komponentu zmiany znikają, a nikt nie pamięta, że były.
Szósty to wybór tego podejścia przy panelu wewnętrznym, gdzie wygląd nie ma znaczenia. Gotowa biblioteka ze stylami jest tam szybsza i mniej kosztowna w utrzymaniu.
Siódmy to usuwanie atrybutów dostępności przy przerabianiu komponentu. Wyglądają na zbędne znaczniki, a odpowiadają za obsługę klawiaturą i czytnikami ekranu, czyli za tę część, dla której ta zależność w ogóle została dodana.
Ósmy to wpisywanie konkretnych odcieni zamiast zmiennych opisujących rolę. Pojedyncze wystąpienie nie boli, natomiast rozchodzi się po projekcie i po roku tryb ciemny wymaga przejścia przez wszystkie komponenty zamiast przez jeden plik.
FAQ
Czy shadcn/ui to biblioteka komponentów?
Nie w zwykłym sensie. To narzędzie kopiujące kod komponentów do Twojego repozytorium, gdzie stają się Twoimi plikami. Nie ma zależności do zaktualizowania ani wersji do podniesienia, a zmiana komponentu jest edycją pliku.
Co zmieniło się w lipcu 2026?
Nowe projekty startują domyślnie na Base UI zamiast na Radiksie. Radix pozostaje w pełni wspierany, istniejące projekty nie muszą migrować, a dla chcących przejść przygotowano umiejętność dla agenta kodującego, przenoszącą projekt stopniowo, komponent po komponencie. W tym samym miesiącu doszła też React Aria jako trzecia równorzędna podstawa.
Czy muszę migrować z Radiksa?
Nie. Zmiana dotyczy wartości domyślnej dla nowych projektów, a nie wygaszania. Projekty oparte o Radix działają dalej i będą działać, więc migracja jest wyborem, a nie koniecznością.
Jak dostać poprawki wprowadzone w źródle?
Ręcznie. Możesz ponownie dodać komponent i porównać różnice albo śledzić zmiany w projekcie źródłowym i przenosić te, które Cię dotyczą. To jest cena pełnej kontroli nad kodem i warto ją policzyć przy większej liczbie komponentów.
Czy da się zbudować własny rejestr?
Tak, mechanizm dystrybucji przyjmuje rejestry inne niż domyślny, więc firma może rozdawać własny system wizualny tym samym poleceniem. Warto wtedy wskazać w konfiguracji bibliotekę mechanizmów, bo bez tego komponenty zostaną potraktowane jako oparte o wartość domyślną.
Opis zmiany fundamentu stoi w dzienniku zmian projektu, a dokumentacja na stronie projektu.