Kurs JavaScript i React · Moduł 7: Stylowanie i animacje

Frameworki komponentów - Budowanie galaktycznych interfejsów z shadcn/ui, Material-UI i Chakra UI

7 min czytania
W tej lekcji7

W naszej podróży przez kosmos technologii frontendowych, frameworki komponentów są jak zaawansowane stacje kosmiczne - gotowe, kompleksowe struktury, które możemy zasiedlić własną logiką i dostosować do naszych potrzeb. W tym module poznamy trzy popularne frameworki komponentów: shadcn/ui, Material-UI i Chakra UI, które pozwalają tworzyć spójne, piękne i funkcjonalne interfejsy użytkownika.

Dlaczego warto używać frameworków komponentów?

Wyobraź sobie, że musisz zbudować zaawansowany statek kosmiczny. Możesz albo konstruować każdą część od podstaw, albo skorzystać z gotowych, przetestowanych i zoptymalizowanych komponentów. Frameworki komponentów dają ci tę drugą możliwość, oferując:

  1. Gotowe komponenty UI - przyciski, formularze, karty, modele, tabele i wiele innych
  2. Spójny design - wszystkie elementy pasują do siebie wizualnie i funkcjonalnie
  3. Dostępność (accessibility) - komponenty są tworzone z myślą o dostępności dla wszystkich użytkowników
  4. Oszczędność czasu - nie musisz reinventować koła za każdym razem
  5. Łatwość utrzymania - aktualizacje, naprawy błędów i nowe funkcje są dostarczane przez społeczność

shadcn/ui - Nowoczesne, niekonwencjonalne podejście do biblioteki komponentów

Czym jest shadcn/ui?

shadcn/ui to unikalne podejście do bibliotek komponentów. W przeciwieństwie do tradycyjnych frameworków, shadcn/ui nie jest biblioteką, którą instalujesz jako zależność. Zamiast tego, to kolekcja komponentów, które kopiujesz bezpośrednio do swojego projektu. To daje ci pełną kontrolę nad kodem oraz możliwość modyfikacji komponentów bez ograniczeń.

Instalacja i konfiguracja shadcn/ui

Aby rozpocząć przygodę z shadcn/ui, wykonaj następujące kroki:

1# Inicjalizacja shadcn/ui w projekcie
2npx shadcn-ui@latest init

Podczas inicjalizacji odpowiesz na kilka pytań dotyczących konfiguracji (style, kolory, itp.). Następnie możesz dodać wybrane komponenty:

1# Dodawanie komponentu przycisku
2npx shadcn-ui@latest add button
3
4# Dodawanie innych komponentów
5npx shadcn-ui@latest add card
6npx shadcn-ui@latest add dialog

Przykład użycia komponentów shadcn/ui

1import { Button } from "@/components/ui/button";
2import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
3
4function MissionControl() {
5  return (
6    <Card>
7      <CardHeader>
8        <CardTitle>Panel Kontroli Misji</CardTitle>
9        <CardDescription>Zarządzaj swoją kosmiczną ekspedycją</CardDescription>
10      </CardHeader>
11      <CardContent>
12        <p>Status systemów: Wszystkie systemy działają prawidłowo</p>
13      </CardContent>
14      <CardFooter>
15        <Button variant="outline" className="mr-2">Anuluj</Button>
16        <Button>Rozpocznij misję</Button>
17      </CardFooter>
18    </Card>
19  );
20}

Zalety shadcn/ui

  • Pełna kontrola - komponenty są w twoim kodzie, możesz je dowolnie modyfikować
  • Brak zależności - nie musisz martwić się o konflikty wersji czy problemy z aktualizacjami
  • Minimalistyczny design - nowoczesny, czysty wygląd komponentów
  • Łatwa customizacja - oparcie na Tailwind CSS ułatwia dostosowanie wyglądu
  • Wsparcie dla ciemnego motywu - wbudowane wsparcie dla trybu ciemnego

Material-UI - Interfejsy w stylu Google

Czym jest Material-UI?

Material-UI (MUI) to popularna biblioteka komponentów React implementująca zasady Material Design stworzone przez Google. To jak budowanie statku kosmicznego według sprawdzonych planów NASA - otrzymujesz interfejs, który jest intuicyjny, spójny i znany użytkownikom na całym świecie.

Instalacja Material-UI

1# Instalacja podstawowych pakietów MUI
2npm install @mui/material @emotion/react @emotion/styled
3
4# Opcjonalnie, dla ikon
5npm install @mui/icons-material

Przykład użycia Material-UI

1import { Button, Card, CardActions, CardContent, Typography } from '@mui/material';
2import RocketLaunchIcon from '@mui/icons-material/RocketLaunch';
3
4function SpaceMission() {
5  return (
6    <Card sx={{ maxWidth: 345, m: 2 }}>
7      <CardContent>
8        <Typography gutterBottom variant="h5" component="div">
9          Misja na Marsa
10        </Typography>
11        <Typography variant="body2" color="text.secondary">
12          Przygotuj się do kosmicznej przygody. Misja na Marsa wymaga odwagi,
13          wiedzy i gotowości na nieznane.
14        </Typography>
15      </CardContent>
16      <CardActions>
17        <Button size="small" color="primary">Szczegóły</Button>
18        <Button
19          size="small"
20          variant="contained"
21          color="primary"
22          startIcon={<RocketLaunchIcon />}
23        >
24          Rozpocznij
25        </Button>
26      </CardActions>
27    </Card>
28  );
29}

Motyw w Material-UI

Material-UI oferuje zaawansowany system tematyczny, który pozwala na dostosowanie kolorów, typografii, zaokrągleń i wielu innych aspektów:

1import { createTheme, ThemeProvider } from '@mui/material/styles';
2
3// Tworzenie własnego motywu
4const theme = createTheme({
5  palette: {
6    primary: {
7      main: '#2196f3', // kosmiczny niebieski
8    },
9    secondary: {
10      main: '#f50057', // gwieździsty róż
11    },
12  },
13  typography: {
14    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
15    h1: {
16      fontSize: '2.5rem',
17      fontWeight: 500,
18    },
19  },
20  shape: {
21    borderRadius: 8,
22  },
23});
24
25// Zastosowanie motywu
26function App() {
27  return (
28    <ThemeProvider theme={theme}>
29      {/* Tutaj umieszczasz komponenty */}
30    </ThemeProvider>
31  );
32}

Zalety Material-UI

  • Bogata biblioteka komponentów - od prostych przycisków po zaawansowane komponenty tabelaryczne
  • Sprawdzony design - implementacja zasad Material Design
  • Zaawansowany system motywów - łatwe dostosowanie wyglądu całej aplikacji
  • Doskonała dokumentacja - szczegółowe przykłady i wyjaśnienia
  • Duża społeczność - łatwo znaleźć pomoc i rozwiązania problemów

Chakra UI - Prostota i dostępność

Czym jest Chakra UI?

Chakra UI to nowoczesna biblioteka komponentów, która stawia na prostotę, modularność i dostępność. To jak budowanie lekkiego, zwinnego pojazdu kosmicznego, który jest jednocześnie bezpieczny i łatwy w obsłudze dla każdego członka załogi, niezależnie od jego możliwości.

Instalacja Chakra UI

1# Instalacja Chakra UI
2npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion

Konfiguracja Chakra UI

1// W głównym pliku aplikacji
2import { ChakraProvider } from '@chakra-ui/react';
3
4function App() {
5  return (
6    <ChakraProvider>
7      {/* Tutaj umieszczasz komponenty */}
8    </ChakraProvider>
9  );
10}

Przykład użycia Chakra UI

1import { Box, Button, Heading, Stack, Text, useColorModeValue } from '@chakra-ui/react';
2
3function SpaceStation() {
4  // Dynamiczne kolory w zależności od trybu (jasny/ciemny)
5  const bgColor = useColorModeValue('blue.50', 'blue.900');
6  const textColor = useColorModeValue('gray.800', 'white');
7
8  return (
9    <Box
10      p={5}
11      shadow="md"
12      borderWidth="1px"
13      borderRadius="md"
14      bg={bgColor}
15      color={textColor}
16    >
17      <Heading size="md" mb={2}>Międzynarodowa Stacja Kosmiczna</Heading>
18      <Text mb={4}>
19        Orbitalny dom astronautów i naukowców z całego świata.
20      </Text>
21      <Stack direction="row" spacing={4}>
22        <Button colorScheme="blue" variant="outline">
23          Informacje
24        </Button>
25        <Button colorScheme="blue">
26          Odwiedź
27        </Button>
28      </Stack>
29    </Box>
30  );
31}

Style i responsywność w Chakra UI

Chakra UI oferuje intuicyjny sposób definiowania responsywnych styli:

1<Stack
2  direction={["column", "row"]} // kolumna na małych ekranach, wiersz na większych
3  spacing={[2, 4, 6]} // różne odstępy dla różnych breakpointów
4>
5  <Box
6    p={[2, 4, 6]} // padding rosnący z rozmiarem ekranu
7    width={["100%", "50%", "33%"]} // szerokość zależna od rozmiaru ekranu
8    bg="blue.500"
9  >
10    Panel 1
11  </Box>
12  <Box
13    p={[2, 4, 6]}
14    width={["100%", "50%", "33%"]}
15    bg="green.500"
16  >
17    Panel 2
18  </Box>
19  <Box
20    p={[2, 4, 6]}
21    width={["100%", "50%", "33%"]}
22    bg="purple.500"
23    display={["none", "block"]} // ukryty na najmniejszych ekranach
24  >
25    Panel 3
26  </Box>
27</Stack>

Zalety Chakra UI

  • Prostota użycia - intuicyjne API i spójna struktura komponentów
  • Dostępność - komponenty zgodne z WCAG i WAI-ARIA
  • Responsywność - łatwe definiowanie styli dla różnych breakpointów
  • Tryb ciemny/jasny - wbudowane wsparcie dla przełączania motywów
  • Customizacja - łatwe dostosowanie systemu designu do potrzeb projektu

Porównanie frameworków - Który wybrać dla swojej kosmicznej misji?

shadcn/ui

Idealny dla:

  • Projektów, gdzie chcesz pełną kontrolę nad kodem komponentów
  • Deweloperów, którzy korzystają z Tailwind CSS
  • Aplikacji wymagających unikalnego designu, ale potrzebujących solidnych fundamentów

Potencjalne wady:

  • Kopiowanie kodu może prowadzić do większej bazy kodu
  • Mniejsza biblioteka komponentów w porównaniu z MUI i Chakra

Material-UI

Idealny dla:

  • Projektów korporacyjnych i enterprise
  • Aplikacji, które powinny być zgodne z designem Google
  • Sytuacji wymagających bogatej biblioteki zaawansowanych komponentów

Potencjalne wady:

  • Bardziej złożone API w niektórych przypadkach
  • Stylowanie wymaga znajomości systemu motywów MUI
  • Większy rozmiar pakietu

Chakra UI

Idealny dla:

  • Projektów, gdzie priorytetem jest dostępność
  • Deweloperów ceniących prostotę i intuicyjność API
  • Aplikacji wymagających szybkiego prototypowania i łatwej customizacji

Potencjalne wady:

  • Mniejsza liczba zaawansowanych komponentów niż MUI
  • Mniejsza społeczność w porównaniu z MUI

Integracja frameworków komponentów z innymi technologiami

Wszystkie omówione frameworki można łączyć z innymi technologiami:

  • Formularze - integracja z React Hook Form lub Formik
  • Zarządzanie stanem - współpraca z Redux, MobX czy React Query
  • Routing - kompatybilność z React Router czy Next.js
  • Animacje - rozszerzenie o Framer Motion czy React Spring

Zadanie praktyczne: Stwórz dashboard kosmicznej misji

Wybierz jeden z omówionych frameworków (shadcn/ui, Material-UI lub Chakra UI) i stwórz dashboard kontroli misji kosmicznej zawierający:

  1. Nawigację główną (np. menu boczne lub górne)
  2. Karty statusu systemów statku kosmicznego
  3. Wykres zużycia paliwa (możesz użyć biblioteki wykresów kompatybilnej z wybranym frameworkiem)
  4. Formularz ustawień misji z różnymi typami pól

Pamiętaj o:

  • Responsywności (dashboard powinien działać na różnych urządzeniach)
  • Dostępności (komponenty powinny być używane zgodnie z wytycznymi dostępności)
  • Spójnym designie (korzystaj z systemu motywów wybranego frameworka)

To zadanie pozwoli ci zrozumieć, jak frameworki komponentów mogą przyspieszyć budowanie złożonych interfejsów i pomoże ci zdecydować, który z nich najlepiej pasuje do twojego stylu pracy i potrzeb projektu.

Kod do tej lekcji: App.jsx
1import React, { useState } from 'react';
2
3// Demonstracja Inline Styles w React
4function InlineStylesDemo() {
5  const [isHovered, setIsHovered] = useState(null);
6  const [theme, setTheme] = useState('dark');
7
8  // Style jako obiekty JavaScript
9  const themes = {
10    dark: {
11      background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)',
12      text: '#ffffff',
13      accent: '#00d4ff',
14      card: 'rgba(255, 255, 255, 0.05)',
15    },
16    light: {
17      background: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)',
18      text: '#1a1a2e',
19      accent: '#667eea',
20      card: 'rgba(0, 0, 0, 0.05)',
21    },
22  };
23
24  const currentTheme = themes[theme];
25
26  // Style kontenerowe
27  const containerStyle = {
28    minHeight: '100vh',
29    background: currentTheme.background,
30    padding: '30px',
31    fontFamily: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",
32    color: currentTheme.text,
33    transition: 'all 0.5s ease',
34  };
35
36  const headerStyle = {
37    textAlign: 'center',
38    marginBottom: '40px',
39  };
40
41  const titleStyle = {
42    fontSize: '2.5em',
43    color: currentTheme.accent,
44    marginBottom: '10px',
45  };
46
47  // Funkcja generująca dynamiczne style dla karty
48  const getCardStyle = (index) => ({
49    background: currentTheme.card,
50    borderRadius: '15px',
51    padding: '25px',
52    marginBottom: '20px',
53    border: `2px solid ${isHovered === index ? currentTheme.accent : 'transparent'}`,
54    transform: isHovered === index ? 'translateY(-5px)' : 'translateY(0)',
55    boxShadow: isHovered === index
56      ? `0 10px 30px ${currentTheme.accent}40`
57      : 'none',
58    transition: 'all 0.3s ease',
59    cursor: 'pointer',
60  });
61
62  const buttonStyle = (isActive) => ({
63    padding: '12px 24px',
64    margin: '0 10px',
65    border: `2px solid ${currentTheme.accent}`,
66    borderRadius: '8px',
67    background: isActive ? currentTheme.accent : 'transparent',
68    color: isActive ? '#000' : currentTheme.accent,
69    fontWeight: 'bold',
70    cursor: 'pointer',
71    transition: 'all 0.3s ease',
72  });
73
74  const features = [
75    {
76      title: 'Dynamiczne wartości',
77      description: 'Style mogą być obliczane na podstawie props, state lub innych danych',
78    },
79    {
80      title: 'Brak konfliktów',
81      description: 'Style inline są automatycznie scopowane do komponentu',
82    },
83    {
84      title: 'Obliczenia w runtime',
85      description: 'Możliwość używania wyrażeń JavaScript do generowania stylów',
86    },
87    {
88      title: 'Łatwe warunkowanie',
89      description: 'Proste dodawanie stylów warunkowych bez dodatkowych klas',
90    },
91  ];
92
93  return (
94    <div style={containerStyle}>
95      <header style={headerStyle}>
96        <h1 style={titleStyle}>Inline Styles w React</h1>
97        <p style={{ color: currentTheme.text, opacity: 0.7 }}>
98          Dynamiczne stylowanie z obiektami JavaScript
99        </p>
100      </header>
101
102      {/* Przełącznik motywu */}
103      <div style={{ textAlign: 'center', marginBottom: '40px' }}>
104        <button
105          style={buttonStyle(theme === 'dark')}
106          onClick={() => setTheme('dark')}
107        >
108          Dark
109        </button>
110        <button
111          style={buttonStyle(theme === 'light')}
112          onClick={() => setTheme('light')}
113        >
114          Light
115        </button>
116      </div>
117
118      {/* Karty z dynamicznymi stylami */}
119      <div style={{ maxWidth: '800px', margin: '0 auto' }}>
120        {features.map((feature, index) => (
121          <div
122            key={index}
123            style={getCardStyle(index)}
124            onMouseEnter={() => setIsHovered(index)}
125            onMouseLeave={() => setIsHovered(null)}
126          >
127            <h3 style={{
128              color: currentTheme.accent,
129              marginBottom: '10px',
130              fontSize: '1.3em'
131            }}>
132              {feature.title}
133            </h3>
134            <p style={{
135              lineHeight: 1.6,
136              opacity: 0.9
137            }}>
138              {feature.description}
139            </p>
140          </div>
141        ))}
142      </div>
143
144      {/* Przykład kodu */}
145      <div style={{
146        maxWidth: '800px',
147        margin: '40px auto',
148        background: currentTheme.card,
149        borderRadius: '15px',
150        padding: '25px',
151        border: `1px solid ${currentTheme.accent}30`,
152      }}>
153        <h3 style={{ color: currentTheme.accent, marginBottom: '15px' }}>
154          Przykład składni:
155        </h3>
156        <pre style={{
157          background: 'rgba(0,0,0,0.3)',
158          padding: '15px',
159          borderRadius: '8px',
160          overflow: 'auto',
161          fontSize: '14px',
162        }}>
163{`const style = {
164  backgroundColor: isActive ? 'blue' : 'gray',
165  padding: \`\${spacing}px\`,
166  transform: \`scale(\${scale})\`
167};
168
169<div style={style}>...</div>`}
170        </pre>
171      </div>
172
173      <footer style={{
174        textAlign: 'center',
175        marginTop: '40px',
176        opacity: 0.7
177      }}>
178        <p>Inline styles są idealne dla dynamicznych, obliczanych stylów</p>
179      </footer>
180    </div>
181  );
182}
183
184export default InlineStylesDemo;

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak najlepiej nadpisać style z biblioteki CSS w React bez użycia !important?

Zadania praktyczne w grze

  • Układanie w pionie

    Ułóż selektory CSS od najniższej do najwyższej specyficzności:

Przydatne artykuły