UI-Komponenten

50 shadcn/ui-Komponenten mit Radix-Primitiven, CVA-Varianten und abgegrenzten Monorepo-Importen

Das Kit enthält 50 vorkonfigurierte shadcn/ui-Komponenten, die auf Radix UI-Primitiven aufbauen, mit Class Variance Authority (CVA) für typsichere Varianten-Verwaltung und Tailwind CSS für das Styling. Die Komponenten befinden sich in einem gemeinsamen packages/ui/-Paket und werden über abgegrenzte Einstiegspunkte importiert, um unerwünschte App-übergreifende Abhängigkeiten zu verhindern.
Diese Seite behandelt die Komponentenarchitektur, abgegrenzte Importe, verfügbare Komponenten und das Hinzufügen neuer Komponenten. Für Farbthemen, siehe Farbthemen & Dark Mode. Für die Tailwind-Konfiguration, siehe Anpassung.

Komponentenarchitektur

Das Komponentensystem wird über components.json konfiguriert, das der shadcn/ui-CLI mitteilt, wie neue Komponenten installiert werden sollen:
components.json — shadcn/ui-Konfiguration
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.js",
    "css": "src/app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "iconLibrary": "lucide",
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "registries": {}
}
Wichtige Konfigurationsentscheidungen:
  • style: "new-york" — Verwendet die New-York-Variante von shadcn/ui (eigenwilliger, etwas anderes Standard-Styling als der "default"-Stil)
  • rsc: true — Komponenten sind standardmäßig mit React Server Components kompatibel
  • cssVariables: true — Farben referenzieren CSS Custom Properties (das Theme-System) statt hartkodierter Tailwind-Farben
  • baseColor: "neutral" — Neutrale Grau-Skala als Basisfarbe

Wie Komponenten funktionieren

Jede Komponente folgt dem gleichen Muster: Ein Radix-UI-Primitiv liefert barrierefreies, unstyltes Verhalten, CVA definiert die Variantenklassen, und Tailwind wendet die eigentlichen Stile an. Das cn()-Utility (aus @nextsaasai/utils) kombiniert Klassen mit korrekter Konfliktauflösung via tailwind-merge.
Radix-UI-Primitiv (Barrierefreiheit, Tastaturnavigation, ARIA)
    |
    v
CVA-Varianten (variant="default" | "destructive" | "outline", size="sm" | "default" | "lg")
    |
    v
Tailwind-Klassen (bg-primary, text-sm, h-10, px-6, ...)
    |
    v
cn()-Merge (className-Prop-Überschreibungen + tailwind-merge-Konfliktauflösung)

Abgegrenzte Importe

Komponenten sind in zwei Bereiche aufgeteilt, um Importe übersichtlich und Bundle-Größen klein zu halten:
Import-PfadInhaltVerwendet von
@nextsaasai/ui/sharedNur geteilte KomponentenJede App
@nextsaasai/ui/boilerplateGeteilt + nur für Boilerplateapps/boilerplate/
Der Shared-Bereich exportiert die grundlegenden Komponenten, die von allen Anwendungen genutzt werden:
packages/ui/src/shared-index.ts — Geteilte Exports
/**
 * @nextsaasai/ui - Shared Components
 *
 * Components available to ALL applications in the monorepo.
 * These are foundational UI elements used across both boilerplate and marketing apps.
 *
 * @scope shared
 */

// Core Form Components
export * from './button'
export * from './checkbox'
export * from './input'
export * from './label'
export * from './radio-group'
export * from './select'
export * from './slider'
export * from './switch'
export * from './textarea'
export * from './toggle'
export * from './toggle-group'

// Layout Components
export * from './accordion'
export * from './aspect-ratio'
export * from './card'
export * from './collapsible'
export * from './separator'
export * from './sheet'
export * from './tabs'
export * from './table'

// Navigation Components
export * from './breadcrumb'
export * from './pagination'
export * from './scroll-area'

// Data Display Components
export * from './avatar'
export * from './badge'
export * from './typography'

// Overlay Components
export * from './popover'
export * from './tooltip'

// Feedback Components
export * from './sonner'

// Theme Components
export * from './theme-toggle'

// Internationalization Components
export * from './flag-icon'

Komponentenkategorien

Geteilte Komponenten

Für alle Anwendungen über @nextsaasai/ui/shared verfügbar (auch im Boilerplate-Bereich enthalten):
KomponenteDateiBeschreibung
Buttonbutton.tsxPrimäres Aktionselement mit 8 Varianten und 5 Größen
Inputinput.tsxTexteingabe mit einheitlichem Rahmen- und Fokus-Styling
Labellabel.tsxFormular-Label mit Unterstützung für deaktivierten Zustand
Selectselect.tsxDropdown-Auswahl mit Radix-Primitiven
Textareatextarea.tsxMehrzeilige Texteingabe
Cardcard.tsxContainer mit Header-, Content- und Footer-Slots
Sheetsheet.tsxAusklappbares Panel (mobile Navigation, Seitenleisten)
Badgebadge.tsxStatusanzeige mit Variantenfarben
Sonnersonner.tsxToast-Benachrichtigungssystem
ThemeToggletheme-toggle.tsxUmschalter für Dark/Light Mode
FlagIconflag-icon.tsxLänder-Flaggen-Icons für i18n

Nur-Boilerplate-Komponenten

Zusätzliche Komponenten, verfügbar über @nextsaasai/ui/boilerplate:
packages/ui/src/boilerplate-index.ts — Boilerplate-Bereich
// ============================================================================

// Alert Components (error messages, notifications in app)
export * from './alert'
export * from './alert-dialog'

// Form Utilities (react-hook-form integration)
export * from './form'

// Modal Components (app modals, confirmations)
export * from './dialog'
export * from './drawer'

// Navigation Components (user menu in dashboard)
export * from './dropdown-menu'
export * from './context-menu'
export * from './menubar'
export * from './command'

// Progress & Loading Components
export * from './progress'
export * from './skeleton'

// Overlay Components (popovers, tooltips)
export * from './popover'

// Data Display Components
export * from './calendar'
export * from './carousel'
export * from './hover-card'
export * from './resizable'

// Input Components
export * from './input-otp'

// Toast Notifications (in-app feedback)
export * from './toast'
export * from './use-toast'
// Note: toaster.tsx available but not exported to avoid conflict with sonner
KomponenteBeschreibung
Alert / AlertDialogFehlermeldungen, Bestätigungsdialoge
Formreact-hook-form-Integration mit Zod-Validierung
DialogModale Fenster für In-App-Interaktionen
DropdownMenuBenutzermenü, Aktionsmenüs im Dashboard
ProgressLadebalken, Upload-Fortschrittsanzeigen
SkeletonLade-Platzhalter-Animationen
Toast / useToastLegacy-Toast-System (Sonner wird für neuen Code bevorzugt)

Button im Detail

Die Button-Komponente demonstriert das CVA-Muster, das in allen Komponenten verwendet wird:
packages/ui/src/button.tsx — Button mit CVA-Varianten
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from '@nextsaasai/utils'

const buttonVariants = cva(
  'inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-3.5 [&_svg]:shrink-0',
  {
    variants: {
      variant: {
        default: 'bg-primary text-background dark:text-foreground/90 hover:text-white',
        destructive: 'bg-red-600 text-white hover:bg-red-700 dark:bg-red-600 dark:hover:bg-red-700',
        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/90',
        accent: 'bg-accent text-accent-foreground hover:bg-accent/90',
        uncolored: 'bg-card text-card-muted-foreground hover:text-card-foreground',
        outline: 'border hover:border-foreground/75',
        ghost: 'border border-transparent bg-primary bg-clip-text text-transparent hover:border-foreground/75 hover:text-foreground',
        link: 'bg-primary bg-clip-text text-transparent underline-offset-8 hover:text-foreground inline flex-none !px-0 !h-auto !w-auto',
      },
      size: {
        sm: 'h-9 px-5 text-xs',
        default: 'h-10 px-6 text-sm',
        md: 'h-11 px-7 text-base',
        lg: 'h-12 px-8 text-base',
        xl: 'h-14 px-11 text-lg',
        icon: 'h-10 w-10',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : 'button'

    // Ensure data-testid is passed through properly
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = 'Button'

export { Button, buttonVariants }

Varianten-Referenz

VarianteErscheinungsbildAnwendungsfall
defaultSolid primärer HintergrundPrimäre Aktionen (Speichern, Erstellen)
destructiveRoter HintergrundGefährliche Aktionen (Löschen, Entfernen)
secondaryGedämpfter HintergrundSekundäre Aktionen (Abbrechen, Zurück)
accentAkzent-HintergrundHervorgehobene sekundäre Aktionen
outlineNur RahmenTertiäre Aktionen, Umschalter
ghostVerlaufstext, Rahmen beim HoverDezente Aktionen, Navigationslinks
linkVerlaufstext, Unterstrich-OffsetInline-Textlinks
uncoloredKarten-HintergrundNeutrale Aktionen in Karten-Kontexten

Verwendungsbeispiele

tsx
import { Button } from '@nextsaasai/ui/boilerplate'

// Primäre Aktion
<Button>Save Changes</Button>

// Destructive mit Größe
<Button variant="destructive" size="sm">Delete Account</Button>

// Als Link (rendert <a> statt <button>)
<Button asChild variant="link">
  <a href="/docs">Read the Docs</a>
</Button>

// Icon-Button
<Button variant="ghost" size="icon">
  <SearchIcon />
</Button>
Die asChild-Prop verwendet Radix' Slot-Komponente, um das Styling des Buttons auf das Kind-Element zu übertragen — nützlich für das Rendern von gestylten <a>-Tags oder Next.js-<Link>-Komponenten.

Card-Muster

Die Card-Komponente verwendet ein Compound-Component-Muster mit separaten Unterkomponenten für jeden Bereich:
packages/ui/src/card.tsx — Card-Komponente
const Card = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      'rounded-md border border-border bg-card text-card-foreground',
      className
    )}
    {...props}
  />
))
Card.displayName = 'Card'
Jeder Teil (Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter) ist eine forwardRef-Komponente mit cn() für das Zusammenführen von Klassen. Verwende sie gemeinsam:
tsx
import { Card, CardHeader, CardTitle, CardContent } from '@nextsaasai/ui/boilerplate'

<Card>
  <CardHeader>
    <CardTitle>Monthly Usage</CardTitle>
  </CardHeader>
  <CardContent>
    <p>You have used 1,234 of 5,000 credits this month.</p>
  </CardContent>
</Card>

Neue Komponenten hinzufügen

1

Komponente installieren

Verwende die shadcn/ui-CLI, um eine neue Komponente zu generieren. Führe dies aus dem Boilerplate-App-Verzeichnis aus:
bash
cd apps/boilerplate
npx shadcn@latest add accordion
Dies generiert die Komponentendatei im konfigurierten ui-Alias-Pfad.
2

In das packages/ui-Verzeichnis verschieben

Verschiebe die generierte Komponente aus dem lokalen components/ui/-Verzeichnis nach packages/ui/src/:
bash
mv src/components/ui/accordion.tsx ../../packages/ui/src/accordion.tsx
3

Den cn-Import aktualisieren

Die generierte Komponente importiert cn aus dem lokalen Pfad. Aktualisiere ihn auf das gemeinsame Paket:
typescript
// Vorher (generiert von der shadcn/ui-CLI)
import { cn } from '@/lib/utils'

// Nachher (gemeinsames Monorepo-Utility)
import { cn } from '@nextsaasai/utils'
4

Im Bereich registrieren

Exportiere die Komponente aus der passenden Bereich-Index-Datei. Für die meisten Boilerplate-Komponenten füge sie zu packages/ui/src/boilerplate-index.ts hinzu:
typescript
// Accordion-Komponente
export * from './accordion'
Für Komponenten, die in allen Apps verwendet werden, füge sie stattdessen zu shared-index.ts hinzu.

Projekt-Komponenten

Neben den gemeinsamen packages/ui/-Komponenten hat die Boilerplate-App eigene Komponenten, die nach Features organisiert sind:
src/components/
├── about/          # About-Seite (Hero, Team, Werte, Timeline)
├── ai/             # KI-Chat-Interface (Chat, Nachrichten, Eingabe, RAG/LLM)
├── auth/           # Authentifizierung (Login-Formulare, Benutzer-Button)
├── blog/           # Blog-UI (Seitenleiste, Tags, Like/Share-Buttons)
├── contact/        # Kontaktseite (Hero, Info, Formular)
├── credits/        # Credit-System (Niedrigstand-Banner, Nutzungszähler)
├── dashboard/      # Dashboard-UI (Seitenleiste, Header, Analytics, Abonnements)
├── demo/           # Demo-Modus (Nav-Item, Demo-Provider)
├── forms/          # Formular-Komponenten (Kontaktformular)
├── home/           # Landingpage (Hero, Features, Newsletter)
├── layout/         # App-Layout (Navbar, Footer)
├── modals/         # Modale Dialoge (Credits erschöpft)
├── payments/       # Zahlungs-UI (Plan-Wechsel-Dialog, Zahlungsfehler)
├── shared/         # Übergreifendes (Hero-Hintergrund)
├── test/           # Test-Utilities (No-Clerk-Script, Konfigurationsfehler)
└── upload/         # Datei-Upload (Drop-Zone, Vorschau, Hooks)
Das sind app-spezifische Komponenten — sie importieren aus @nextsaasai/ui/boilerplate für grundlegende UI-Elemente und ergänzen diese um Business-Logik.

Wichtige Dateien

DateiZweck
components.jsonshadcn/ui-CLI-Konfiguration (Stil, Pfade, Aliase)
packages/ui/src/shared-index.tsGeteilte Komponentenexporte (30 Komponenten)
packages/ui/src/boilerplate-index.tsBoilerplate-Bereich-Exports (geteilt + 18 zusätzliche)
packages/ui/src/button.tsxButton-Komponente mit 8 CVA-Varianten
packages/ui/src/card.tsxCard-Compound-Komponente (6 Unterkomponenten)
packages/utils/src/index.tscn()-Utility (clsx + tailwind-merge)