React CRM Template: Pipeline, Prognose, Firmenseiten

Du baust ein CRM-Frontend, für einen Kunden oder für dein eigenes Produkt, und suchst nach einem react crm template. Die Treffer sind Theme-Marktplätze mit Admin-Kits aus Dutzenden Seiten, Open-Source-CRMs mit eigenem Backend und ein paar Starter, die ein Kanban-Board mit Beispielzahlen zeigen. Was du brauchst, ist kleiner und schwieriger: eine Deal-Pipeline, deren Summen etwas bedeuten, eine Möglichkeit, einen Deal zu bearbeiten, ohne das Board zu verlassen, und eine Firmenseite, die die ganze Kundenbeziehung abbildet. Dieses Tutorial baut diese drei Screens in Next.js aus Blöcken von Wingo UI, verbunden mit Server Actions, und zeigt den fertigen Code.
Was gehört in ein React CRM Template?
Der größte Teil des Nutzens eines CRM steckt in drei Screens. Alles andere (Aufgaben, E-Mail-Sync, Reports) kann später kommen.
- Das Pipeline-Board. Deals als Karten in Spalten pro Phase, jede Spalte mit Anzahl, Summe und gewichteter Summe, darüber eine Zusammenfassung: offene Pipeline, gewichtete Prognose, diesen Monat gewonnen, Abschlussquote. Filter nach Verantwortlichen und Abschlussdatum. Eine Listenansicht für alle, die in Zeilen denken.
- Das Deal-Sheet. Ein Klick auf eine Karte öffnet ein Panel mit Wert, Phase, Abschlussdatum, Verantwortlichem, Kontakt, Notizen und dem Aktivitätsverlauf. Wer es mit ungespeicherten Änderungen schließt, wird vorher gefragt.
- Der Firmendatensatz. Eine Seite pro Kunde mit den wichtigsten Fakten, den Kontakten, den Deals, einer Aktivitäts-Timeline, Dateien und Notizen.
Die Details entscheiden, ob das Vertriebsteam dem Tool vertraut. Wer einen Deal auf „Verloren“ ablegt, sollte nach dem Grund gefragt werden, denn ein Report über Verlustgründe ist wertlos, wenn die Hälfte der Gründe fehlt. Ein Deal, der wochenlang in einer Phase liegt, sollte veraltet aussehen. Schlägt das Speichern fehl, sollte die Karte zurückspringen und das auch melden, statt ein Board zu hinterlassen, das lügt.
Solltest du ein CRM-Template kaufen oder aus Blöcken zusammensetzen?
Setz es aus Blöcken zusammen, wenn das CRM ein Teil eines größeren Produkts ist, betreib Twenty, wenn du ein ganzes CRM mit Backend willst, und kauf ein Kit, wenn du am ersten Tag viele fertige Screens haben möchtest. Die Fakten stammen von den öffentlichen Seiten der Projekte, Stand Oktober 2026:
Twenty ist die bessere Wahl, wenn du ein CRM betreiben und erweitern willst und kein Frontend bauen möchtest. Ein komplettes Kit ist besser, wenn du Dutzende fertige Screens willst und die Beispieldaten ersetzen wirst. Blöcke passen, wenn das CRM in einem Agentur-Tool, einer Rechnungs-App oder einem vertikalen SaaS steckt und zum Rest passen muss. Ein Hinweis zu Refine: Laut README von examples/app-crm ist das volle Beispiel in die Enterprise Edition gewandert, und das MIT-Repo behält eine kleinere Community-Version in examples/app-crm-minimal.
Wie strukturierst du ein Next.js CRM Template?
Ein nextjs crm template braucht zwei Routen in der Admin-Routengruppe aus unserem Next.js Admin-Dashboard-Tutorial. Dort richten wir auch die Shell, den LinkProvider und die Datenzugriffsschicht mit verifySession() ein, die unten genutzt werden.
Installier die beiden Blöcke und die Shell. Die CLI ergänzt alles, was sie importieren, auch die Deal Pipeline und das Kanban darunter:
Wie baust du die Seite für die Deal-Pipeline?
Fang mit den Datenstrukturen an. Die Phasen stehen in der Konfiguration, denn eine geänderte Wahrscheinlichkeit ist eine Produktentscheidung und sollte wie jede andere Codeänderung durchs Review gehen. Die IDs der Phasen müssen über alle Pipelines eindeutig sein: Die Seite ordnet einen Deal der Pipeline zu, zu der seine Phase gehört.
Die Seite ist eine Server-Komponente. Sie prüft die Session, lädt alles parallel und liest ?deal=, damit ein Link das Sheet eines Deals öffnen kann. Deine Query-Helfer (listDeals, listOwners, listCompanies) geben CrmDeal[], CrmOwner[] und CrmPipelineCompany[] zurück. Gib jeder Firma ein href wie /clients/<id>, dann verlinkt das Deal-Sheet auf ihren Datensatz.
Der Block ist eine Client-Komponente, also stecken die Callbacks in einer kleinen View. Jeder Handler gibt das Promise der Server Action zurück: Die Karte zeigt einen Spinner, solange sie läuft, und wird es abgelehnt, springt sie mit einem Toast zurück.
Zwei Details in den Handlern übersieht man leicht. onDealMove feuert auch, wenn jemand Karten innerhalb einer Spalte umsortiert (move.from.id === move.to.id), deshalb überspringt die View diese Fälle. Sonst würde jedes Umsortieren stage_entered_at zurücksetzen und damit den Hinweis auf veraltete Deals und das Datum des Gewinns löschen. Und onDealSave liefert eine Notiz aus dem Sheet als neuesten activity-Eintrag mit kind: "note". Ihre ID ist stabil, also speicherst du Notizen per Upsert über diese ID: Ein späteres Speichern desselben Deals schickt dieselbe Notiz noch einmal.
Schick IDs und einfache Felder an die Actions, nie den ganzen Deal: Eine Server Action ist ein öffentlicher Endpunkt, also nimmt sie nur an, was sie validiert. Hier die Verschiebung, die am häufigsten läuft:
saveDeal, createDeal und deleteDeal folgen demselben Muster (saveDeal validiert die optionale note mit z.object({ id: z.string(), text: z.string().max(5000) })). createDeal gibt toCrmDeal(row) zurück, damit der gespeicherte Deal den Entwurf auf dem Board ersetzt. Das Board bleibt unkontrolliert (defaultDeals), also musst du die Seite nach einer Verschiebung nicht revalidieren: Der optimistische State zeigt das Ergebnis schon.
$ npx wingo-ui@latest add crm-pipeline-pageWie funktioniert die gewichtete Prognose?
Die gewichtete Summe einer Phase ist die Summe aus Betrag mal Wahrscheinlichkeit über ihre Deals. Die Wahrscheinlichkeit kommt von der Phase, außer der Deal setzt eine eigene probability, die sie überschreibt. Gewonnene Deals zählen voll, verlorene null. Mit den Phasen von oben:
Die Zusammenfassung hat vier Kacheln: offene Pipeline, gewichtete Prognose, im Zeitraum gewonnen (standardmäßig der aktuelle Monat, datiert über stageEnteredAt) und die Abschlussquote, also gewonnene Deals geteilt durch gewonnene plus verlorene im selben Zeitraum. Bei der Deal Pipeline und bei PipelineSummary ersetzt showWeighted={false} die gewichtete Kachel durch den durchschnittlichen offenen Deal. Deals in einer anderen Währung werden getrennt summiert, mit einem Hinweis, und nie umgerechnet. Ohne einen Wechselkurs, den du selbst kontrollierst, ist das die einzige ehrliche Voreinstellung.
Die Wahrscheinlichkeiten pro Phase sind die Schwachstelle. Leg sie anhand deiner eigenen abgeschlossenen Deals fest (wie viele der Deals, die „Angebot gesendet“ erreicht haben, wurden gewonnen?) und prüf sie jedes Quartal neu. Behandle die Zahlen oben als Platzhalter, bis deine eigene Historie sie ersetzt.
Um dieselbe Prognose auf die Startseite des Dashboards zu bringen, renderst du die Zusammenfassung allein. Sie ist eine Client-Komponente, die einfache Daten bekommt, also kann eine Server-Seite sie direkt rendern. Für eigene Kacheln liefert computePipelineStats(deals, stages) aus derselben Datei die Zahlen hinter der Zusammenfassung. Die Datei beginnt mit "use client", also ruf die Funktion aus Client-Code auf: Eine Server-Komponente, die sie importiert, bekommt eine Client-Referenz statt einer Funktion.
Wie baust du die Firmenseite?
Die CRM Contact Page bekommt einen Datensatz: die Firma, ihre Kontakte, Deals, Aktivitäten, Dateien und Notizen. Für alles, was du weglässt, greift sie auf Beispieldaten zurück, also gib jeden Teil mit, auch people und currentUser.
getClientRecord gibt ein CrmContactSample ({ company, contacts, deals, activity, files, notes }) zurück, dazu seine Position in der Kundenliste. Gib jedem Deal href: "/deals?deal=<id>", dann öffnet eine Zeile im Tab Deals das Sheet dieses Deals auf dem Board.
Zwei Dinge erledigst du auf dem Server. Notizen kommen als HTML aus dem Rich-Text-Editor, also bereinige sie, bevor du sie speicherst oder renderst. Und gib onUpload mit, sobald du einen Dateispeicher hast, denn ohne diesen Callback simuliert der Tab Files den Upload nur.
$ npx wingo-ui@latest add crm-contact-pageWie funktioniert das CRM auf dem Smartphone?
Auf dem Smartphone zeigt das Board jeweils eine Phase, das Ziehen startet mit einem langen Druck, und alle Menüs, Sheets und Dialoge öffnen sich von unten. Im Detail:
- Board. Jeweils eine Phase auf 85% der Breite, die nächste schaut am Rand herein, und über eine Reihe Chips springst du zwischen den Phasen. Ein Deal hebt sich erst nach einem langen Druck von 250ms an, damit ein Wischen weiter scrollt. Das Menü ⋯ (Move to, Mark as won, Mark as lost) öffnet sich als Bottom Sheet.
- Zusammenfassung. Ein Raster aus 2 x 2 Kacheln, das sich mit einem Tipp auf seinen Chevron zu einer Zeile zusammenklappt.
- Deal-Sheet und Dialoge. Das Sheet wird zu einem hohen Bottom Sheet, der Pipeline-Wechsler und der Dialog für den Verlustgrund öffnen sich von unten, und aus New deal wird ein +-Button.
- Firmenseite. Die Aktionen im Header klappen in ⋯ zusammen, das Seitenpanel wird zum Tab Details, und die Deal-Tabelle wird zu Karten.
Wie das Touch-Ziehen hinter dem Board funktioniert, erklärt unser Tutorial zu dnd kit und Touch-Drag auf dem Smartphone. Das Board selbst, mit WIP-Limits und Verschieben per Tastatur, behandelt der Guide zum React Kanban Board.
Kannst du das Deal Pipeline Kanban allein nutzen?
Ja. Die CRM Pipeline Page ist der volle Screen mit Header, Filtern, Deal-Sheet und Dialog für neue Deals. Die Deal Pipeline ist die Sales Pipeline UI, die du in React-Apps überall einbetten kannst: das Board mit der Zusammenfassung, der Listenansicht und den Chips für Verantwortliche, und nichts drumherum. Nimm sie für ein deal pipeline kanban in einem Kundenportal oder auf einer Projektseite, wo ein ganzer CRM-Screen zu viel wäre.
Die Props, die zählen, wenn du sie allein nutzt:
stagesplusdefaultValue(unkontrolliert) odervaluemitonValueChange(kontrolliert).onValueChangebekommt das neue Array und denDealMove, der bei neu angelegten Deals und bei Rollbacks undefined ist.onDealMovemit demselben Vertrag wie auf der Seite: Gib ein Promise zurück, solange die Karte speichern soll, lass es fehlschlagen (reject), damit sie zurückspringt, oder gibfalsezurück, um die Verschiebung abzulehnen.onDealClick, um dein eigenes Panel zu öffnen. Ohne diesen Callback folgt eine Karte mithrefdem Link.persistKey, um Ansicht, Filter nach Verantwortlichen und eingeklappte Spalten pro Person zu merken.getDealActionsfür zusätzliche Einträge im Menü ⋯ nach Move to, Mark as won und Mark as lost, undrenderCardmit den Teilen vonDealCard, wenn die Standardkarte die falschen Felder zeigt.
$ npx wingo-ui@latest add deal-pipelineFür ein komplettes react crm dashboard template mit KPIs, Tabellen und Einstellungen rund um diese Screens startest du mit dem Next.js Admin-Dashboard-Tutorial. Die Kategorie Build zeigt die anderen Screens Schritt für Schritt.
Was baust du als Nächstes?
Installier die Blöcke mit npx wingo-ui@latest add crm-pipeline-page crm-contact-page, schließ listDeals an deine Datenbank an und verdrahte zuerst moveDeal, denn diese Action nutzen die Leute am häufigsten. Die CRM-Blöcke sind Pro (Preise). Wenn du mit Claude Code oder Cursor baust, verbinde den MCP-Server von Wingo UI, damit der Agent die echten Props jedes Blocks liest, statt sie zu raten.
Häufige Fragen
Gibt es ein kostenloses React CRM Template?
Ja. Refine veröffentlicht ein CRM-Beispiel auf Basis von React, Ant Design und einer GraphQL-API (Stand Oktober 2026 ist die volle Version in die Enterprise Edition gewandert, eine minimale Community-Version unter MIT-Lizenz bleibt), und Twenty ist ein komplettes Open-Source-CRM, größtenteils unter AGPLv3, mit eigenem Backend. Die CRM-Blöcke von Wingo UI aus diesem Tutorial sind Pro.
Wie berechnet man eine gewichtete Pipeline-Prognose?
Multiplizier den Betrag jedes offenen Deals mit seiner Gewinnwahrscheinlichkeit und addier die Ergebnisse. Die Wahrscheinlichkeit kommt meist von der Phase des Deals, und ein Deal kann sie überschreiben; gewonnene Deals zählen voll, verlorene mit null.
Woher sollen die Wahrscheinlichkeiten pro Phase kommen?
Aus deinen eigenen abgeschlossenen Deals: pro Phase der Anteil der Deals, die sie erreicht haben und später gewonnen wurden. Ohne Historie startest du mit groben Schätzungen und kalibrierst neu, sobald ein paar Monate abgeschlossener Deals vorliegen.
Kann ich ein React CRM Template mit meinem eigenen Backend nutzen?
Ja, wenn das Template nur die UI liefert. Die Blöcke von Wingo UI bekommen ihre Daten über Props und melden jede Änderung über Callbacks wie onDealMove und onNoteSave, also funktionieren sie mit Server Actions, einer REST-API oder GraphQL.
Wie funktioniert ein Board für die Sales-Pipeline auf dem Smartphone?
Zeig jeweils eine Phase und lass die nächste am Rand hereinschauen, ergänz Chips, um zwischen den Phasen zu springen, und heb Karten erst nach einem langen Druck an, damit ein Wischen weiter scrollt. Für alle, die nicht ziehen wollen, gibt es ein Menü „Move to“ im Bottom Sheet.
- CRM
- Next.js
- Sales-Pipeline
- Kanban
- Vorlagen


