34 UI-Bibliotheken integrieren – Von Bootstrap bis Headless Components

Eine React-App von Grund auf zu stylen ist zeitaufwendig. Buttons, Formulare, Modals, Dropdowns – alles muss designed, entwickelt und getestet werden. UI-Bibliotheken lösen dieses Problem: Sie liefern fertige, getestete Komponenten mit konsistentem Design. Der Trade-off: Man kauft Produktivität mit Flexibilitätsverlust und Bundle-Size.

Das Spektrum reicht von CSS-Frameworks wie Bootstrap (bringt Styles, React-Bindings optional) über vollständige Component-Libraries wie Material UI (React-first, opinionated Design) bis zu Headless-Libraries wie Radix UI (Logik ohne Styles, maximale Freiheit).

34.1 Das Spektrum: CSS-Frameworks vs. Component Libraries vs. Headless

CSS-Frameworks (Bootstrap, Tailwind CSS) - Liefern: Utility-Classes oder vordefinierte Klassen - Integration: CSS-Datei einbinden - React-Komponenten: Optional via Wrapper-Libraries - Flexibilität: Hoch (nur CSS, eigene Komponenten)

Component Libraries (Material UI, Ant Design, Chakra UI) - Liefern: Fertige React-Komponenten mit Styling - Integration: npm-Paket, importiere Komponenten - Design: Opinionated (Material Design, Ant Design System) - Flexibilität: Mittel (Theme-System, aber Design-Sprache fix)

Headless Libraries (Radix UI, Headless UI, React Aria) - Liefern: Logik, Accessibility, keine Styles - Integration: npm-Paket, eigenes CSS/Tailwind - Design: Agnostic - Flexibilität: Maximal (komplette Style-Kontrolle)

34.2 Bootstrap: Der Klassiker mit React-Bindings

Bootstrap ist primär ein CSS-Framework. Für React gibt es react-bootstrap – React-Komponenten, die Bootstrap-Styles nutzen.

34.2.1 Integration: CDN vs. npm

Option 1: CDN (schnell für Prototypen)

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React</title>
    
    <!-- Bootstrap CSS via CDN -->
    <link 
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" 
      rel="stylesheet"
    >
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
// Mit nativen Bootstrap-Klassen
function App() {
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <button className="btn btn-primary">Click me</button>
        </div>
      </div>
    </div>
  );
}

Nachteile: - JavaScript-Komponenten (Modals, Dropdowns) brauchen Bootstrap JS + jQuery - Keine TypeScript-Typen - Kein React-Lifecycle-Integration

Option 2: npm + react-bootstrap (empfohlen)

npm install react-bootstrap bootstrap
// main.tsx
import 'bootstrap/dist/css/bootstrap.min.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
// App.tsx
import { Container, Row, Col, Button, Card, Modal } from 'react-bootstrap';
import { useState } from 'react';

function App() {
  const [show, setShow] = useState(false);
  
  return (
    <Container>
      <Row className="mt-4">
        <Col md={6}>
          <Card>
            <Card.Body>
              <Card.Title>React Bootstrap Example</Card.Title>
              <Card.Text>
                Using Bootstrap components as React components.
              </Card.Text>
              <Button variant="primary" onClick={() => setShow(true)}>
                Open Modal
              </Button>
            </Card.Body>
          </Card>
        </Col>
      </Row>
      
      <Modal show={show} onHide={() => setShow(false)}>
        <Modal.Header closeButton>
          <Modal.Title>Modal Title</Modal.Title>
        </Modal.Header>
        <Modal.Body>Modal content goes here</Modal.Body>
        <Modal.Footer>
          <Button variant="secondary" onClick={() => setShow(false)}>
            Close
          </Button>
          <Button variant="primary">
            Save Changes
          </Button>
        </Modal.Footer>
      </Modal>
    </Container>
  );
}

Vorteile: - React-native Komponenten - TypeScript-Support - Kein jQuery - Event-Handler sind React-Events

34.2.2 Bootstrap Theming

Bootstrap nutzt CSS-Variablen für Theming:

// src/styles/custom.scss
// Bootstrap-Variablen überschreiben
$primary: #5e35b1;
$secondary: #26a69a;
$font-family-sans-serif: 'Inter', system-ui, sans-serif;

@import 'bootstrap/scss/bootstrap';
// main.tsx
import './styles/custom.scss';  // Statt bootstrap.min.css

Oder zur Runtime mit CSS-Variablen:

/* src/index.css */
:root {
  --bs-primary: #5e35b1;
  --bs-secondary: #26a69a;
  --bs-border-radius: 0.5rem;
}

34.3 Material UI: Das vollständige Design-System

Material UI (MUI) implementiert Googles Material Design als React-Komponenten. Umfangreich, opinionated, produktionsreif.

npm install @mui/material @emotion/react @emotion/styled

MUI nutzt Emotion für CSS-in-JS.

// App.tsx
import { 
  ThemeProvider, 
  createTheme, 
  CssBaseline,
  Container,
  Button,
  TextField,
  Card,
  CardContent,
  Typography
} from '@mui/material';

const theme = createTheme({
  palette: {
    primary: {
      main: '#1976d2',
    },
    secondary: {
      main: '#dc004e',
    },
  },
  typography: {
    fontFamily: 'Roboto, Arial, sans-serif',
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />  {/* Normalisiert Browser-Styles */}
      
      <Container maxWidth="md" sx={{ mt: 4 }}>
        <Card>
          <CardContent>
            <Typography variant="h4" gutterBottom>
              Material UI Example
            </Typography>
            
            <TextField 
              label="Email" 
              variant="outlined" 
              fullWidth 
              sx={{ mb: 2 }}
            />
            
            <TextField 
              label="Password" 
              type="password" 
              variant="outlined" 
              fullWidth 
              sx={{ mb: 2 }}
            />
            
            <Button variant="contained" color="primary" fullWidth>
              Login
            </Button>
          </CardContent>
        </Card>
      </Container>
    </ThemeProvider>
  );
}

34.3.1 MUI Theme Customization

// theme.ts
import { createTheme } from '@mui/material';

export const theme = createTheme({
  palette: {
    mode: 'light',
    primary: {
      main: '#5e35b1',
      light: '#9162e4',
      dark: '#280680',
    },
    secondary: {
      main: '#26a69a',
      light: '#64d8cb',
      dark: '#00766c',
    },
    background: {
      default: '#f5f5f5',
      paper: '#ffffff',
    },
  },
  typography: {
    fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
    h1: {
      fontSize: '2.5rem',
      fontWeight: 600,
    },
    button: {
      textTransform: 'none', // Keine Uppercase-Buttons
    },
  },
  shape: {
    borderRadius: 8,
  },
  components: {
    MuiButton: {
      styleOverrides: {
        root: {
          borderRadius: 8,
          padding: '10px 24px',
        },
      },
      defaultProps: {
        disableElevation: true,
      },
    },
    MuiCard: {
      styleOverrides: {
        root: {
          boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
        },
      },
    },
  },
});
// App.tsx
import { ThemeProvider } from '@mui/material';
import { theme } from './theme';

function App() {
  return (
    <ThemeProvider theme={theme}>
      {/* App */}
    </ThemeProvider>
  );
}

34.3.2 sx Prop: Inline-Styling mit Theme-Access

MUI’s sx prop ermöglicht Theme-aware Inline-Styles:

import { Box, Typography } from '@mui/material';

function Component() {
  return (
    <Box
      sx={{
        bgcolor: 'primary.main',      // Theme-Farbe
        color: 'primary.contrastText', // Automatischer Kontrast
        p: 2,                          // padding: theme.spacing(2)
        mt: 4,                         // margin-top: theme.spacing(4)
        borderRadius: 1,               // theme.shape.borderRadius
        '&:hover': {
          bgcolor: 'primary.dark',
        },
      }}
    >
      <Typography variant="h6">Styled Box</Typography>
    </Box>
  );
}
Shorthand CSS Property Theme-Wert
p padding theme.spacing(n)
m margin theme.spacing(n)
bgcolor background-color theme.palette.*
color color theme.palette.*

34.3.3 TypeScript mit MUI

import { Button, ButtonProps } from '@mui/material';

// Custom Button mit eigenen Props
interface CustomButtonProps extends ButtonProps {
  loading?: boolean;
}

function CustomButton({ loading, children, ...props }: CustomButtonProps) {
  return (
    <Button disabled={loading} {...props}>
      {loading ? 'Loading...' : children}
    </Button>
  );
}

34.4 PrimeReact: Enterprise-UI für Business-Apps

PrimeReact bietet umfangreiche Komponenten für Business-Anwendungen: DataTables, Charts, Forms.

npm install primereact primeicons
// main.tsx
import 'primereact/resources/themes/lara-light-indigo/theme.css';
import 'primereact/resources/primereact.min.css';
import 'primeicons/primeicons.css';
// App.tsx
import { Button } from 'primereact/button';
import { InputText } from 'primereact/inputtext';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Card } from 'primereact/card';
import { useState } from 'react';

interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
}

function App() {
  const [products] = useState<Product[]>([
    { id: 1, name: 'Laptop', price: 999, category: 'Electronics' },
    { id: 2, name: 'Mouse', price: 29, category: 'Electronics' },
    { id: 3, name: 'Keyboard', price: 79, category: 'Electronics' },
  ]);
  
  return (
    <div className="p-4">
      <Card title="PrimeReact Example" className="mb-4">
        <div className="p-fluid">
          <div className="p-field mb-3">
            <label htmlFor="search">Search</label>
            <InputText id="search" placeholder="Search products..." />
          </div>
          
          <Button label="Add Product" icon="pi pi-plus" className="p-button-success" />
        </div>
      </Card>
      
      <Card title="Products">
        <DataTable value={products} paginator rows={10} responsiveLayout="scroll">
          <Column field="id" header="ID" sortable />
          <Column field="name" header="Name" sortable />
          <Column field="price" header="Price" sortable body={(data) => `$${data.price}`} />
          <Column field="category" header="Category" sortable />
        </DataTable>
      </Card>
    </div>
  );
}

34.4.1 PrimeReact Theming

PrimeReact nutzt vorgefertigte Themes. Custom-Themes via CSS-Variablen:

/* src/theme.css */
:root {
  --primary-color: #5e35b1;
  --primary-color-text: #ffffff;
  --surface-0: #ffffff;
  --surface-50: #fafafa;
  --surface-100: #f5f5f5;
  --text-color: #212121;
  --border-radius: 6px;
}

Oder Designer-Tool nutzen: https://www.primefaces.org/designer/primereact

34.5 Chakra UI: Developer Experience im Fokus

Chakra UI kombiniert Component Library mit Utility-Props wie Tailwind.

npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion
// main.tsx
import { ChakraProvider } from '@chakra-ui/react';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <ChakraProvider>
      <App />
    </ChakraProvider>
  </React.StrictMode>
);
// App.tsx
import { 
  Box, 
  Button, 
  Container, 
  Heading, 
  Input, 
  Stack,
  Card,
  CardBody,
  Text
} from '@chakra-ui/react';

function App() {
  return (
    <Container maxW="container.md" py={8}>
      <Card>
        <CardBody>
          <Heading mb={4}>Chakra UI Example</Heading>
          
          <Stack spacing={3}>
            <Input placeholder="Email" size="lg" />
            <Input placeholder="Password" type="password" size="lg" />
            
            <Button colorScheme="purple" size="lg">
              Login
            </Button>
          </Stack>
        </CardBody>
      </Card>
      
      {/* Utility Props wie Tailwind */}
      <Box 
        mt={4} 
        p={4} 
        bg="purple.50" 
        borderRadius="md"
        _hover={{ bg: 'purple.100' }}
      >
        <Text color="purple.800">
          Hover me to see background change
        </Text>
      </Box>
    </Container>
  );
}

34.5.1 Chakra Custom Theme

// theme.ts
import { extendTheme } from '@chakra-ui/react';

export const theme = extendTheme({
  colors: {
    brand: {
      50: '#f5e9ff',
      100: '#dbb8ff',
      500: '#5e35b1',
      900: '#280680',
    },
  },
  fonts: {
    heading: '"Inter", sans-serif',
    body: '"Inter", sans-serif',
  },
  components: {
    Button: {
      baseStyle: {
        fontWeight: 'semibold',
      },
      defaultProps: {
        colorScheme: 'brand',
      },
    },
  },
});
// main.tsx
import { ChakraProvider } from '@chakra-ui/react';
import { theme } from './theme';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <ChakraProvider theme={theme}>
    <App />
  </ChakraProvider>
);

34.6 Headless UI: Maximale Flexibilität

Headless UI (von Tailwind Labs) liefert Logik und Accessibility, kein Styling.

npm install @headlessui/react
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, useState } from 'react';

function Example() {
  const [isOpen, setIsOpen] = useState(false);
  
  return (
    <>
      <button
        onClick={() => setIsOpen(true)}
        className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
      >
        Open Dialog
      </button>
      
      <Transition appear show={isOpen} as={Fragment}>
        <Dialog 
          as="div" 
          className="relative z-10" 
          onClose={() => setIsOpen(false)}
        >
          <Transition.Child
            as={Fragment}
            enter="ease-out duration-300"
            enterFrom="opacity-0"
            enterTo="opacity-100"
            leave="ease-in duration-200"
            leaveFrom="opacity-100"
            leaveTo="opacity-0"
          >
            <div className="fixed inset-0 bg-black bg-opacity-25" />
          </Transition.Child>
          
          <div className="fixed inset-0 overflow-y-auto">
            <div className="flex min-h-full items-center justify-center p-4">
              <Transition.Child
                as={Fragment}
                enter="ease-out duration-300"
                enterFrom="opacity-0 scale-95"
                enterTo="opacity-100 scale-100"
                leave="ease-in duration-200"
                leaveFrom="opacity-100 scale-100"
                leaveTo="opacity-0 scale-95"
              >
                <Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
                  <Dialog.Title className="text-lg font-medium leading-6 text-gray-900">
                    Payment successful
                  </Dialog.Title>
                  
                  <div className="mt-2">
                    <p className="text-sm text-gray-500">
                      Your payment has been successfully submitted.
                    </p>
                  </div>
                  
                  <div className="mt-4">
                    <button
                      type="button"
                      className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200"
                      onClick={() => setIsOpen(false)}
                    >
                      Got it, thanks!
                    </button>
                  </div>
                </Dialog.Panel>
              </Transition.Child>
            </div>
          </div>
        </Dialog>
      </Transition>
    </>
  );
}

Headless UI übernimmt: - Focus-Management - Keyboard-Navigation - ARIA-Attribute - Open/Close-State - Animation-Transitions

Du schreibst: Alle Styles.

34.7 Vergleich: Wann welche Library?

Library Bundle Size Learning Curve Design Freedom Best For
Bootstrap ~25KB CSS Niedrig Mittel Quick Prototypes, interne Tools
Material UI ~300KB Mittel Niedrig Material Design Apps, Enterprise
PrimeReact ~400KB Mittel Niedrig Data-heavy Business Apps
Chakra UI ~200KB Niedrig Hoch Developer Experience, Rapid Dev
Ant Design ~600KB Hoch Niedrig Chinese Market, Admin Panels
Headless UI ~20KB Mittel Maximal Custom Designs, Tailwind Users
Radix UI ~50KB Hoch Maximal Design Systems, Full Control

34.7.1 Entscheidungsbaum

34.8 Style-Kollisionen vermeiden

Problem: Globale CSS-Regeln verschiedener Libraries kollidieren.

// ❌ Falsch: Bootstrap + Material UI gleichzeitig
import 'bootstrap/dist/css/bootstrap.min.css';
import '@mui/material/styles';

// Buttons haben konkurrierende Styles
<button className="btn btn-primary">Bootstrap</button>
<Button variant="contained">Material UI</Button>

Lösungen:

1. CSS Modules (Scoping)

// Button.module.css
.button {
  composes: btn btn-primary from 'bootstrap/dist/css/bootstrap.min.css';
  /* Überschreibungen */
  border-radius: 8px;
}

2. CSS-in-JS Libraries isolieren automatisch

Material UI (Emotion) und Chakra generieren unique Klassen-Namen → keine Kollisionen.

3. Prefix für globale Styles

// Prefix alle Bootstrap-Klassen
.bootstrap-scope {
  @import 'bootstrap/scss/bootstrap';
}
<div className="bootstrap-scope">
  <button className="btn btn-primary">Scoped Bootstrap</button>
</div>

34.9 Performance: Bundle Size optimieren

UI Libraries sind oft groß. Tree-Shaking hilft.

❌ Falsch: Default Import importiert alles

import * as MaterialUI from '@mui/material';

<MaterialUI.Button>Click</MaterialUI.Button>

Bundle enthält alle MUI-Komponenten, auch wenn nur Button genutzt wird.

✓ Richtig: Named Imports

import { Button, TextField } from '@mui/material';

<Button>Click</Button>

Webpack/Vite können ungenutzte Komponenten entfernen.

Noch besser: Direct Imports (wenn Tree-Shaking nicht funktioniert)

import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';

34.9.1 Code-Splitting für Libraries

Lazy-load heavy Komponenten:

import { lazy, Suspense } from 'react';

// DataTable ist groß, nur laden wenn gebraucht
const DataTable = lazy(() => import('primereact/datatable').then(m => ({ 
  default: m.DataTable 
})));

function App() {
  const [showTable, setShowTable] = useState(false);
  
  return (
    <div>
      <button onClick={() => setShowTable(true)}>Show Table</button>
      
      {showTable && (
        <Suspense fallback={<div>Loading table...</div>}>
          <DataTable value={data} />
        </Suspense>
      )}
    </div>
  );
}

34.10 Vendor Lock-in vermeiden

Problem: App ist komplett abhängig von Material UI. Wechsel zu Chakra? Hunderte Komponenten müssen umgeschrieben werden.

Lösung: Abstraction Layer

// components/Button.tsx - Eigener Wrapper
import { Button as MuiButton, ButtonProps as MuiButtonProps } from '@mui/material';

interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  children: React.ReactNode;
  onClick?: () => void;
}

export function Button({ variant = 'primary', size = 'md', ...props }: ButtonProps) {
  // Map eigene Props zu MUI-Props
  const muiVariant = variant === 'primary' ? 'contained' : 
                      variant === 'secondary' ? 'outlined' : 'text';
  
  const muiSize = size === 'sm' ? 'small' : 
                  size === 'lg' ? 'large' : 'medium';
  
  return <MuiButton variant={muiVariant} size={muiSize} {...props} />;
}
// App nutzt eigenen Button
import { Button } from './components/Button';

<Button variant="primary" size="lg">Click me</Button>

Jetzt ist nur Button.tsx abhängig von MUI. Wechsel zu Chakra? Nur eine Datei ändern.

34.11 TypeScript: Library-spezifische Typen

Jede Library bringt eigene Type-Definitionen.

// Material UI
import { ButtonProps } from '@mui/material';

function CustomButton(props: ButtonProps) {
  return <Button {...props} />;
}

// Erweitern mit eigenen Props
interface CustomButtonProps extends ButtonProps {
  loading?: boolean;
}
// PrimeReact
import { DataTableProps } from 'primereact/datatable';

interface CustomTableProps extends DataTableProps {
  onExport?: () => void;
}
// Chakra UI
import { BoxProps } from '@chakra-ui/react';

interface CardProps extends BoxProps {
  title: string;
}

function Card({ title, children, ...boxProps }: CardProps) {
  return (
    <Box p={4} borderWidth={1} borderRadius="md" {...boxProps}>
      <Text fontSize="xl" fontWeight="bold">{title}</Text>
      {children}
    </Box>
  );
}

34.12 Häufige Fehler

Fehler 1: CSS-Imports in falscher Reihenfolge

// ❌ Falsch: Eigenes CSS vor Library-CSS
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';

// App.css wird von Bootstrap überschrieben!

// ✓ Richtig: Library zuerst, dann Overrides
import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';

Fehler 2: ThemeProvider vergessen

// ❌ Falsch: MUI-Komponenten ohne Provider
function App() {
  return <Button variant="contained">Click</Button>;
  // Default-Theme, keine Custom-Colors
}

// ✓ Richtig: ThemeProvider umschließt App
function App() {
  return (
    <ThemeProvider theme={customTheme}>
      <Button variant="contained">Click</Button>
    </ThemeProvider>
  );
}

Fehler 3: Globale Styles überschreiben versehentlich Library

/* ❌ Falsch: Zu generische Selektoren */
button {
  background: red;  /* Überschreibt alle Library-Buttons! */
}

/* ✓ Richtig: Spezifische Klassen */
.my-button {
  background: red;
}

Fehler 4: Icons nicht importiert

// ❌ Falsch: PrimeReact-Icons fehlen
import { Button } from 'primereact/button';

<Button icon="pi pi-check" />  // Icon nicht sichtbar!

// ✓ Richtig: Icons importieren
import 'primeicons/primeicons.css';

Fehler 5: Incompatible Library-Versionen

# ❌ Falsch: MUI v5 mit React 17
npm install @mui/material@5.0.0
# Braucht React 18!

# ✓ Richtig: Kompatible Versionen prüfen
npm install @mui/material@latest react@latest react-dom@latest

34.13 Dark Mode mit Libraries

Jede Library hat eigene Dark-Mode-Mechanismen.

Material UI:

import { createTheme, ThemeProvider } from '@mui/material';
import { useState } from 'react';

function App() {
  const [mode, setMode] = useState<'light' | 'dark'>('light');
  
  const theme = createTheme({
    palette: {
      mode,
    },
  });
  
  return (
    <ThemeProvider theme={theme}>
      <button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>
        Toggle Dark Mode
      </button>
    </ThemeProvider>
  );
}

Chakra UI:

import { ChakraProvider, useColorMode, Button } from '@chakra-ui/react';

function ThemeToggle() {
  const { colorMode, toggleColorMode } = useColorMode();
  
  return (
    <Button onClick={toggleColorMode}>
      Toggle {colorMode === 'light' ? 'Dark' : 'Light'}
    </Button>
  );
}

PrimeReact:

// Lade verschiedene Theme-CSS je nach Mode
const [theme, setTheme] = useState('lara-light-indigo');

useEffect(() => {
  import(`primereact/resources/themes/${theme}/theme.css`);
}, [theme]);

<button onClick={() => setTheme(
  theme === 'lara-light-indigo' ? 'lara-dark-indigo' : 'lara-light-indigo'
)}>
  Toggle Theme
</button>

34.14 Migration-Strategie: Library wechseln

Schrittweise Migration statt Big Bang:

  1. Abstraction Layer einführen (eigene Komponenten)
  2. Neue Library parallel installieren
  3. Route für Route migrieren
  4. Alte Library entfernen wenn komplett migriert
// Phase 1: Beide Libraries koexistieren
import { Button as OldButton } from 'old-library';
import { Button as NewButton } from 'new-library';

// Route 1: Noch alte Library
<Route path="/old-dashboard" element={<OldDashboard />} />

// Route 2: Schon neue Library
<Route path="/new-dashboard" element={<NewDashboard />} />

UI-Bibliotheken sind Werkzeuge, keine Religion. Bootstrap für interne Tools? Perfekt. Material UI für Enterprise-App mit Google-Aesthetik? Gut. Headless UI für komplett custom Design? Auch gut. Die beste Library ist die, die zur Team-Expertise, Projektanforderungen und Deadline passt – nicht die mit den meisten GitHub-Stars.