React Native Reusables — komponenty shadcn/ui w React Native
React Native Reusables przenosi model shadcn/ui na React Native: kod komponentu trafia do twojego repozytorium, a nie do zależności. Opisujemy CLI, trzydzieści primitywów, wybór między NativeWind i Uniwind oraz to, co warto wiedzieć o dostępności.
Biblioteki komponentów mają wadę, którą odkrywa się dopiero przy trzeciej prośbie projektanta. Komponent robi 90% tego, co potrzebujesz, a pozostałe 10% jest zamknięte w cudzej paczce — więc obudowujesz go warstwą nadpisań, walczysz ze specyficznością stylów, a przy większej zmianie i tak przepisujesz go od zera. Na dodatek aktualizacja biblioteki bywa zmianą wyglądu całej aplikacji, o której nikt cię nie pytał.
Na froncie webowym odpowiedzią na to okazał się shadcn/ui, który zaproponował coś nieoczywistego: nie instalujesz biblioteki, kopiujesz kod. Komponent trafia do twojego repozytorium jako zwykły plik, który możesz otworzyć, zrozumieć i zmienić. Nie ma warstwy nadpisań, bo nie ma czego nadpisywać — to twój kod.
React Native Reusables przenosi ten model na aplikacje mobilne, dokładając do tego stylowanie klasami Tailwinda przez NativeWind. To bardzo dobre miejsce, żeby zacząć projekt mobilny, i jednocześnie projekt, w którym kilka decyzji trzeba podjąć świadomie na starcie.
Stan projektu
Repozytorium żyje dziś pod adresem founded-labs/react-native-reusables — projekt przeszedł z konta osobistego autora do organizacji, więc jeśli macie gdzieś zapisany stary adres, warto go poprawić. 8651 gwiazdek, 314 forków, licencja MIT, start w grudniu 2023.
Utrzymanie jest zdrowe. Ostatnie commity na gałęzi main pochodzą z 2 lipca 2026 i nie są to porządki po bocie — wśród nich są dodanie obsługi ograniczonego ruchu, poprawa dostępności we wszystkich komponentach korzystających z animacji oraz aktualizacja primitywów. Otwartych zgłoszeń jest 16, co przy blisko dziewięciu tysiącach gwiazdek jest liczbą wyjątkową i mówi o porządnej segregacji zgłoszeń więcej niż jakiekolwiek zapewnienie.
Wydania idą per paczka w ramach monorepa: rn-primitives@1.4.0 z 28 marca 2026 i cli@0.7.0 z 14 marca 2026, a wcześniej seria łatek CLI z grudnia 2025 i stycznia 2026. Projekt jest wspierany przez program open source Vercela i sponsorowany przez CodeRabbit, a zgłoszenia bezpieczeństwa idą na adres organizacji, nie przez publiczne zgłoszenie.
Model: kod jest twój i odpowiedzialność też
Zanim przejdziemy do narzędzi, warto zrozumieć konsekwencję tego modelu, bo bywa przemilczana w entuzjastycznych opisach.
Skoro kod komponentu trafia do twojego repozytorium, to od tej chwili jest twoim kodem. Poprawka błędu w komponencie u autorów nie dotrze do ciebie sama — nie ma zależności, którą podniesiesz. Musisz świadomie zdecydować, czy śledzisz zmiany w rejestrze i przenosisz je do siebie, czy przyjmujesz stan z dnia skopiowania jako punkt startowy i dalej idziesz własną drogą. Obie odpowiedzi są dobre, ale trzeba ją dać, a nie odkryć po roku.
Autorzy stawiają to wprost, i to w nietypowym miejscu — w polityce bezpieczeństwa. Jest tam osobna klauzula o kopiowaniu kodu, mówiąca, że repozytorium pozwala kopiować fragmenty kodu, a użytkownicy są odpowiedzialni za przejrzenie i odpowiedzialne użycie tego kodu we własnych projektach, przy czym opiekunowie nie odpowiadają za podatności wynikłe z jego użycia. To uczciwe i warto to potraktować dosłownie: skopiowany komponent przechodzi u was normalny przegląd kodu, tak jak każdy inny wkład.
CLI: trzy polecenia, z których jedno wyróżnia się szczególnie
Narzędzie wiersza poleceń to @react-native-reusables/cli (obecnie 0.7.1, MIT). Uruchamia się bez instalacji, dowolnym menedżerem paczek:
npx @react-native-reusables/cli@latest add button
pnpm dlx @react-native-reusables/cli@latest doctor
bunx --bun @react-native-reusables/cli@latest initadd wstawia komponenty do projektu. Opcje są dokładnie takie, jakich się oczekuje: -y pomija pytania, -o nadpisuje istniejące pliki, -p wskazuje katalog docelowy, -c zmienia katalog roboczy, a -a dorzuca wszystkie dostępne komponenty naraz.
init zakłada nowy projekt gotowy do pracy z tym zestawem albo sprawdza i naprawia istniejącą konfigurację.
doctor jest tym poleceniem, które chciałbym widzieć w każdym projekcie tego typu. Diagnozuje projekt pod kątem brakujących plików, błędnej konfiguracji i wymaganych zależności, a opcjonalnie sam doinstalowuje to, czego brakuje. Ma też przełącznik --summary, jeśli chcesz samo podsumowanie. W ekosystemie React Native, gdzie połowa problemów to niezgodne wersje i zapomniany wpis w konfiguracji Metro, narzędzie mówiące „brakuje ci tego i tego" oszczędza godziny szukania po forach.
Jedna rzecz architektoniczna warta odnotowania: rejestr komponentów jest serwowany przez stronę z dokumentacją. Polecenie add pobiera kod przez sieć, a nie z lokalnie zainstalowanej paczki — widać to wprost w instrukcji dla osób rozwijających projekt, którym każe się uruchomić lokalnie aplikację z dokumentacją, żeby add działało. Praktycznie znaczy to, że dodawanie komponentów wymaga dostępu do sieci, a w środowisku odciętym od internetu trzeba ten krok wykonać wcześniej i skopiowane pliki potraktować jako część repozytorium.
Rozwidlenie, o którym trzeba zdecydować na starcie
To najważniejsza decyzja w tym projekcie i łatwo ją przeoczyć, bo w opisach zwykle wspomina się tylko o NativeWindzie. Zajrzenie do rejestru pokazuje jednak dwa równoległe zestawy komponentów: jeden dla nativewind, drugi dla uniwind. CLI ma odpowiadającą temu opcję --styling-library, przyjmującą jedną z tych dwóch wartości, a domyślnie próbującą wykryć, czego używasz.
NativeWind jest w tym ekosystemie rozwiązaniem ugruntowanym — przenosi klasy Tailwinda do React Native i ma za sobą lata użycia. Uniwind jest młodszą propozycją w tej samej niszy. Projekt obsługuje oba i to dobra wiadomość, ale konsekwencja jest jednoznaczna: wybór, którego dokonasz przy pierwszym add, decyduje o wariancie kodu, który wyląduje w twoim repozytorium. Zmiana zdania po dwudziestu skopiowanych komponentach to nie przełączenie flagi, a przepisanie ich wszystkich. Warto więc świadomie sprawdzić stan obu bibliotek w momencie startu projektu i podjąć decyzję, zamiast pozwolić autodetekcji zdecydować za siebie.
Co dokładnie dostajesz
Pod komponentami leży warstwa primitywów bez stylów — dokładny odpowiednik tego, czym Radix jest dla shadcn/ui na froncie webowym. Lista zależności rejestru wymienia trzydzieści paczek @rn-primitives/*, wszystkie przypięte do tej samej wersji 1.5.2:
- Nakładki i warstwy —
dialog,alert-dialog,popover,hover-card,tooltip,portal. - Menu i nawigacja —
dropdown-menu,context-menu,menubar,navigation-menu,toolbar,tabs. - Formularze —
checkbox,radio-group,select,switch,slider,toggle,toggle-group,label. - Wyświetlanie treści —
accordion,collapsible,avatar,aspect-ratio,progress,separator,table,toast,slot.
Osobom pracującym na froncie webowym spodoba się jeszcze jedno: warstwa pomocnicza to dokładnie ta sama trójka, którą znasz z shadcn/ui — class-variance-authority do wariantów, clsx do warunkowego składania klas i tailwind-merge do rozwiązywania konfliktów. Ikony pochodzą z lucide-react-native. Innymi słowy: jeśli twój zespół pisze już w tej konwencji na webie, próg wejścia w wersję mobilną jest niski, bo idiomy są te same.
Na tej podstawie zbudowane jest trzydzieści dwa gotowe komponenty. Warto zobaczyć całą listę, bo pokazuje, jak blisko jest to odpowiednikowi z frontu webowego: accordion, alert, alert-dialog, aspect-ratio, avatar, badge, button, card, checkbox, collapsible, context-menu, dialog, dropdown-menu, hover-card, icon, input, label, menubar, native-only-animated-view, popover, progress, radio-group, select, separator, skeleton, switch, tabs, text, textarea, toggle, toggle-group i tooltip.
Dwie pozycje z tej listy warto skomentować, bo są specyficzne dla React Native. text jest komponentem, bo w React Native styl tekstu nie dziedziczy się tak jak w przeglądarce — potrzebny jest jawny element, który to ujednolica. A native-only-animated-view istnieje właśnie po to, by obsłużyć różnicę między platformą mobilną a webem, gdzie część animacji ma się nie wykonywać.
W rejestrze poza komponentami są też katalogi z blokami i przykładami: przykładów użycia jest trzydzieści jeden, a bloków dziewięć — i wszystkie dziewięć dotyczy uwierzytelniania (formularz logowania, rejestracji, odzyskiwania i zmiany hasła, weryfikacji adresu, połączeń społecznościowych oraz menu użytkownika).
Jak bardzo idiomy są wspólne z frontem webowym, najlepiej pokazuje plik pomocniczy rejestru. To dosłownie ten sam cn(), którego używasz w projekcie shadcn/ui:
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}Czego nie ma — i projekt mówi to sam
To sekcja, którą najbardziej doceni każdy, kto porównuje ten zestaw z shadcn/ui przed decyzją. W repozytorium leży osobny plik z zasobami społeczności, którego zadaniem jest wprost wypełnić brakujące elementy shadcn/ui. Innymi słowy: autorzy sami prowadzą listę tego, czego u nich nie ma.
Trzy pozycje są oznaczone jako do zrobienia, bez żadnej propozycji zastępczej: combobox, command (czyli paleta poleceń) oraz resizable. Jeśli twój projekt opiera się na wyszukiwarce z podpowiedziami albo palecie poleceń, to jest robota do wykonania po twojej stronie.
Pozostałe braki mają wskazane rozwiązania z zewnątrz i ta lista sama w sobie jest wartościowa, bo oszczędza wieczoru szukania:
- Kalendarz — Flash Calendar. Wykresy — Victory Native. Tabela danych — TanStack Table. Wybór daty — React Native DateTimePicker.
- Formularze — React Hook Form, ze wskazaniem na instrukcję dla React Native.
- Kod jednorazowy —
input-otp-native, opisany jako zgodny z NativeWindem. - Szuflada i arkusz dolny — Universal Bottom Sheet albo nawigacja szufladowa z React Navigation.
- Powiadomienia — Sonner Native (port Sonnera) albo Burnt, korzystający z elementów natywnych.
- Karuzela — tu jest tylko odnośnik do artykułu opisującego, jak ją zbudować na
Animated.ScrollView. To jedyna pozycja, przy której nie ma nawet biblioteki.
Jest też sekcja z szablonami startowymi, na razie z jedną pozycją — gotową aplikacją opartą o Supabase z logowaniem, rejestracją i profilem.
Uczciwość tej listy jest argumentem za projektem, nie przeciw. Znacznie lepiej dowiedzieć się o braku palety poleceń z pliku w repozytorium niż po dwóch tygodniach pracy.
Na czym to stoi
Wersje zależności rejestru mówią, że projekt jest trzymany blisko czoła ekosystemu: React 19.2.3, React Native 0.85.3, Expo w linii 56 (widać to po expo-router ~56.2.11), nativewind ^4.2.2, uniwind ^1.6.3, react-native-reanimated ~4.3.1 wraz z react-native-worklets. Wymagany Node to 20.11.0 lub nowszy, a monorepo prowadzone jest przez Turbo i pnpm.
Dyscyplina przypinania jest przy tym godna uwagi: wszystkie trzydzieści primitywów ma dokładnie jedną, tę samą wersję, a nie zakresy. Przy bibliotece komponentów to właściwa decyzja — zapobiega sytuacji, w której dwa primitywy w jednym drzewie zależności rozjeżdżają się o wersję minor i przestają współpracować.
Zwróć uwagę, że react-native-web jest zadeklarowany jako opcjonalna zależność równorzędna. To znaczy, że komponenty są przewidziane także do działania w przeglądarce — jeśli macie aplikację mobilną i jej webowy wariant, jeden zestaw komponentów obsłuży oba.
Dostępność, czyli temat, który właśnie stał się obowiązkiem
Dwa z najświeższych commitów dotyczą dokładnie tego: dodania obsługi ograniczonego ruchu oraz poprawy dostępności we wszystkich komponentach korzystających z animacji. Warto wiedzieć, dlaczego to jest ważniejsze niż zwykła poprawka.
Ustawienie „ogranicz ruch" w systemie to nie preferencja estetyczna — dla części osób animacje przesuwające duże obszary ekranu wywołują realne dolegliwości, od zawrotów głowy po nudności. Komponent, który animuje otwarcie okna dialogowego bez sprawdzenia tego ustawienia, jest dla takiej osoby niewygodny w sposób, którego nie da się obejść po jej stronie.
Dla polskich firm dochodzi wymiar formalny. Wymogi dostępności produktów i usług cyfrowych — w tym aplikacji mobilnych — są przedmiotem regulacji europejskiej wdrożonej do polskiego porządku prawnego, a zakres podmiotów objętych obowiązkiem stopniowo się rozszerza. Nie wchodząc w szczegóły, które i tak trzeba sprawdzić dla konkretnej działalności: budowanie aplikacji na komponentach, których autorzy sami dbają o obsługę ustawień dostępności systemu, jest tańsze niż nadrabianie tego przy audycie. To jeden z mocniejszych argumentów za tym projektem, a jednocześnie taki, którego nie zobaczysz w opisie funkcji.
Dwie rzeczy, które zauważyłem w repozytorium
Pierwsza jest zaletą i znakiem czasów. Repozytorium zawiera katalogi konfiguracyjne dla czterech różnych narzędzi programowania z pomocą modeli — .claude, .codex, .cursor i .gemini — oraz plik .mcp.json z konfiguracją serwera MCP. To zgodne z lipcowym commitem dodającym inspektor środowiska i integrację MCP. Dla zespołu pracującego z asystentami znaczy to, że projekt sam podpowiada narzędziom, jak się w nim poruszać.
Druga to drobiazg, ale wart wzmianki, bo pokazuje, że warto czytać to, co się kopiuje. W zakomitowanym .mcp.json ścieżka do dziennika wywołań wskazuje na katalog domowy konkretnej osoby — /Users/zach/.argent/mcp-calls.log. Nikomu to nie zaszkodzi, ale u ciebie ta konfiguracja nie zadziała bez zmiany ścieżki. To dobra ilustracja zasady z ich własnej polityki bezpieczeństwa: przejrzyj, co bierzesz.
Warto też odnotować, że rejestr ma wśród zależności @clerk/expo oraz expo-auth-session. Znaczy to, że część gotowych bloków dotyczy uwierzytelniania i jest zbudowana wokół konkretnego, komercyjnego dostawcy tożsamości. Nie musisz go używać — komponenty interfejsu są niezależne — ale jeśli skopiujesz blok logowania, sprawdź, co dokładnie ciągnie za sobą, zanim wpiszesz to w architekturę.
Pułapki w jednym miejscu
- Poprawki nie przychodzą same. Skopiowany kod jest twój — zdecyduj, czy śledzisz zmiany w rejestrze, i zapisz tę decyzję.
- Wybór między NativeWindem i Uniwindem jest wiążący. Zmiana po skopiowaniu wielu komponentów to ich przepisanie, nie przełączenie flagi.
- Polecenie
addpobiera kod przez sieć z rejestru serwowanego przez stronę dokumentacji. W środowisku bez internetu zaplanuj to wcześniej. - Adres repozytorium się zmienił — projekt jest dziś w organizacji
founded-labs. - Bloki uwierzytelniania są zbudowane wokół komercyjnego dostawcy tożsamości. Sprawdź zależności bloku, zanim go wpiszesz w architekturę.
.mcp.jsonzawiera ścieżkę z cudzego katalogu domowego. Popraw, jeśli korzystasz z tej konfiguracji.- Projekt trzyma się czoła ekosystemu — React 19.2, RN 0.85, Expo 56. To zaleta, ale przy starszym projekcie oznacza konieczność aktualizacji przed startem.
- Brak komponentów
combobox,commandiresizable— oznaczone w repozytorium jako do zrobienia, bez zastępników. - Karuzela to tylko odnośnik do artykułu, nie gotowe rozwiązanie.
- Wszystkie dziewięć bloków dotyczy uwierzytelniania. Innych gotowych większych kawałków interfejsu na razie nie ma.
- Wymagany Node to 20.11.0 lub nowszy.
- Nie ma jednej wersji „biblioteki", którą można przypiąć — wydania idą per paczka w monorepie. Zapisz sobie, z jakiego dnia pochodzi skopiowany kod.
Podsumowanie
React Native Reusables rozwiązuje w aplikacjach mobilnych ten sam problem, który shadcn/ui rozwiązał na froncie webowym, i robi to konsekwentnie: dostajesz kod, nie zależność, a wraz z nim pełną kontrolę i pełną odpowiedzialność. Dla zespołu, który pisze już w konwencji Tailwinda i wariantów, jest to najkrótsza droga do spójnego interfejsu mobilnego.
- Trzydzieści primitywów bez stylów jako fundament — nakładki, menu, formularze i elementy treści, wszystkie przypięte do jednej wersji.
- Te same idiomy co na webie —
class-variance-authority,clsxitailwind-merge, więc wiedza zespołu przenosi się bez przeszkolenia. - Polecenie
doctor, które diagnozuje konfigurację projektu i potrafi doinstalować brakujące zależności. - Obsługa dwóch bibliotek stylowania — NativeWind i Uniwind, z jawnym przełącznikiem zamiast milczącego założenia.
- Dostępność traktowana jako praca do wykonania, z obsługą systemowego ograniczenia ruchu w komponentach animowanych.
- Wspólny zestaw dla aplikacji mobilnej i webowej, dzięki opcjonalnej obsłudze
react-native-web.
Projekt jest wydany na licencji MIT — najbardziej permisywnej z popularnych. Możesz używać go komercyjnie, modyfikować i dostarczać klientom bez obowiązku otwierania własnego kodu, co przy modelu kopiowania kodu do repozytorium jest warunkiem wręcz koniecznym: skopiowany komponent staje się częścią twojego projektu i MIT nie stawia temu żadnych przeszkód. Warto tylko pamiętać, że ta sama licencja zdejmuje z autorów odpowiedzialność, a ich własna polityka bezpieczeństwa przypomina o tym wprost — kod, który kopiujesz, przechodzi u ciebie przegląd na twoich zasadach.