Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Blocks

CRM Contact Page

Blocks

CRM Contact Page React block for Tailwind CSS v4

Checkout PageCRM Pipeline Page
Live props
Content
primaryContactId
locale
currency
State
defaultTab
defaultFavorite
defaultFollowing
loading
Behavior
previousShortcut
nextShortcut
noteShortcut
autoFocusNote
listHref
invoiceHref
contactHref
animateIn
Layout
showAside
factsLayout
headerSticky
Appearance
tone
radius
Code
import { CrmContactPage } from "@/components/blocks/crm-contact-page"

<CrmContactPage />
  1. Home
  2. Components
  3. Blocks
  4. CRM Contact Page
Pro

CRM Contact Page React block for Tailwind CSS v4

v1.0.1·Updated in 1.9.0

A React CRM contact page: a company record with facts and actions, tabs for overview, activity, deals, files and notes, and a details panel.

The header shows the company with its status, a star and a follow toggle, key facts (copy the tax ID, open the last invoice) and actions: Email and Call open the mail app and the phone, New deal opens a validated dialog (title, value, stage, close date) and the new deal lands in the deals tab, the rest (New invoice, Add contact, Export record, Archive) fold into ⋯ when they do not fit and always on phones. Double click the name, press F2 or tap the pencil to rename it. The pager walks to the previous and next client (keys are off by default; the demo binds Alt + arrows). Once the header scrolls away a glass bar keeps the name and the primary action. The tabs (arrows, Home and End) switch Overview, Activity, Deals, Files and Notes; the panel slides in and the counts follow the data. Overview: the company details with copy buttons, the contacts, the open deals (View all jumps to the tab) and the last four events. Activity: write a comment (@ mentions a colleague, ⌘ Enter sends) and it lands at the top of today; the chips filter emails, calls, meetings and invoices and announce the count. Deals: a sortable table (cards on phones) with the open total. Files: drop or pick files, they upload with progress and join the list; preview, download or delete (asked first). Notes: a rich text editor with mentions, ⌘ Enter or Save note saves; pin, edit or delete a note from ⋯ (delete has an undo toast). The side panel shows the primary contact (call, email, WhatsApp), billing, tags (remove with ×, add from the field) and the team; on phones it is the Details tab. Archiving shows an alert with Restore and makes the record read-only. Failed saves roll back with a toast. Sections rise in once on mount; reduced motion keeps everything still.

CRM Contact Page is a Pro React block in the React blocks category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add crm-contact-page, together with Alert, Avatar, Badge, Button, Comment Thread and 32 more and the npm packages motion, lucide-react, react-hook-form and zod.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add crm-contact-page

CRM Contact Page is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import CrmContactPage from @/components/blocks/crm-contact-page.

// app/(admin)/clients/[id]/page.tsx (the shell lives in app/(admin)/layout.tsx: <AdminShell>{children}</AdminShell>)
"use client"

import { CrmContactPage, type CrmNote } from "@/components/blocks/crm-contact-page"

export default function ClientPage() {
  return (
    <CrmContactPage
      previousShortcut="alt+arrowleft"
      nextShortcut="alt+arrowright"
      onNoteSave={async (note: CrmNote) => {
        await fetch(`/api/clients/c01/notes/${note.id}`, { method: "PUT", body: JSON.stringify(note) })
      }}
      onTagsChange={async (tags) => {
        await fetch("/api/clients/c01", { method: "PATCH", body: JSON.stringify({ tags }) })
      }}
    />
  )
}

Props

  • company
    CrmCompany

    The record ({ id, name, cui, regCom, status, industry, city, address, website, email, phone, iban, bank, owner, tags, createdAt, balance, revenueYtd, lastInvoice, lastPayment, overdueInvoices, paymentTermDays, followers, archived }); defaults to CRM_CONTACT_SAMPLE.company (Tech Solutions Inc.).

  • contacts
    ContactData[]

    The people at the company; defaults to CRM_CONTACT_SAMPLE.contacts (Daniel Brooks, Laura Price, Sam Porter).

  • primaryContactIddefault "daniel-brooks"
    string

    The contact in the side panel card, listed first with the Primary badge; defaults to the first contact.

  • deals
    CrmContactDeal[]

    The client's deals ({ id, title, stageId, amount, currency, probability, owner, expectedCloseDate, href }); defaults to CRM_CONTACT_SAMPLE.deals (3).

  • stages
    CrmDealStage[]

    The pipeline stages the deals point to ({ id, name, probability, kind }); defaults to CRM_CONTACT_STAGES (B2B sales).

  • activity
    CrmActivity[]

    Timeline items with a kind (email, call, meeting, invoice, payment, stage, comment, note, file) for the icon and the filters; defaults to CRM_CONTACT_SAMPLE.activity (14).

  • files
    FileItem[]

    The record's files; defaults to CRM_CONTACT_SAMPLE.files (6).

  • notes
    CrmNote[]

    Notes ({ id, author, createdAt, content (HTML), pinned, editedAt }); defaults to CRM_CONTACT_SAMPLE.notes (3).

  • people
    CommentAuthor[]

    Who can be @mentioned in comments and notes; defaults to CRM_CONTACT_TEAM.

  • currentUser
    CommentAuthor

    The signed-in user: the composer avatar, the author of new notes and comments; defaults to Ana Pop.

  • tab
    "overview" | "activity" | "deals" | "files" | "notes"

    The open tab, controlled; pair it with onTabChange.

  • defaultTabdefault "overview"
    "overview" | "activity" | "deals" | "files" | "notes"

    The tab open first while uncontrolled.

  • onTabChange
    (tab: CrmContactTab) => void

    Called when a tab is picked (also by View all and Add a note).

  • pagerdefault "3 of 128"
    EntityPager | null

    Previous / next client ({ index, total, onPrevious, onNext, previousHref, nextHref }); null hides it.

  • previousShortcutdefault ""
    string

    Key for the previous client, e.g. alt+arrowleft; empty binds nothing (the demo binds Alt + arrows).

  • nextShortcutdefault ""
    string

    Key for the next client, e.g. alt+arrowright; empty binds nothing.

  • noteShortcutdefault "mod+enter"
    string

    Saves the note from inside the editor (shown as ⌘ Enter or Ctrl + Enter); empty binds nothing.

  • showAsidedefault true
    boolean

    The side panel with the primary contact, billing, tags and team (the Detalii tab on phones).

  • factsLayoutdefault "strip"
    "strip" | "grid" | "tiles"

    The header facts: one scrolling strip, a grid, or gray tiles (grid and tiles fold after 4 on phones).

  • headerStickydefault "condensed"
    "none" | "condensed"

    condensed pins a glass bar with the name and the primary action once the header scrolls away.

  • defaultUploads
    UploadFile[]

    Uploads already running when the page opens; entries without a picked file finish on a timer (the files example).

  • autoFocusNotedefault false
    boolean

    The note editor takes focus when the notes tab mounts.

  • defaultFavoritedefault true
    boolean

    The header star starts on.

  • defaultFollowingdefault true
    boolean

    The follow toggle starts on (you appear in the team list).

  • listHrefdefault "/clients"
    string

    Where Clients in the breadcrumb goes.

  • invoiceHrefdefault "/invoices/new?client=<id>"
    string

    Where New invoice goes (header menu and billing).

  • contactHrefdefault "/contacts/new?client=<id>"
    string

    Where Add contact goes.

  • onTitleChange
    (title: string) => (void | Promise<unknown>)

    Renaming from the header; a rejection restores the name and shows the error. Simulated by default.

  • onAction
    (action: CrmContactAction, company: CrmCompany) => (void | Promise<unknown>)

    Every header action. Archive and restore are optimistic (a rejection rolls back with a toast); export shows a loading toast.

  • onNoteSave
    (note: CrmNote) => (void | Promise<unknown>)

    A new note (new id) or a changed one (edit, pin); a rejection keeps the draft or rolls back with a toast.

  • onNoteDelete
    (note: CrmNote) => (void | Promise<unknown>)

    Deleting a note: removed at once, with an undo toast; a rejection brings it back.

  • onComment
    (body: string, context: { mentions: string[]; }) => (void | Promise<unknown>)

    A comment from the activity composer; the composer keeps the text until it resolves.

  • onUpload
    (file: File, context: { signal, onProgress }) => Promise<unknown>

    Uploads a picked file; done files join the list. Default: a pretend upload of about 1.6 s.

  • onFileDelete
    (file: FileItem) => (void | Promise<unknown>)

    Deleting a file after the confirmation; the row fades while it runs.

  • onFileOpen
    (file: FileItem) => void

    Clicking a file; default opens its preview url in a new tab.

  • onDealCreate
    (values: CrmNewDealValues) => (void | Promise<unknown>)

    The new deal dialog's submit; a rejection shows its message in the dialog.

  • onTagsChange
    (tags: string[]) => (void | Promise<unknown>)

    Tags added or removed in the side panel; optimistic, rolled back on rejection.

  • onFavoriteChange
    (favorite: boolean) => (void | Promise<unknown>)

    The header star.

  • onFollowingChange
    (following: boolean) => (void | Promise<unknown>)

    The follow toggle.

  • labelsdefault "DEFAULT_CRM_CONTACT_PAGE_LABELS"
    Partial<CrmContactPageLabels>

    Every visible string (English by default); CRM_CONTACT_PAGE_LABELS_RO is the ready Romanian set. Nested keys translate the composed items.

  • localedefault "en-US"
    string

    Intl locale for money, numbers and dates.

  • currencydefault "USD"
    string

    The currency of the balance, revenue and deals.

  • nowdefault "useNow()"
    Date | number

    The reference time for relative times and the day headings; the demo pins Sep 24, 2026 16:40.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The accent of the primary actions, the tab indicator, the chips, the editor and the upload progress.

  • radiusdefault "md"
    "sm" | "md" | "lg"

    The panels (12, 16 or 24px), the contact card, the dropzone, the editor and the dialog.

  • loadingdefault false
    boolean

    The header, the sections and the side panel as skeletons.

  • animateIndefault true
    boolean

    The header, the panel and the side sections rise in once on mount; off in thumbnails and under reduced motion.

  • linkComponentdefault "<a>"
    (props: LinkComponentProps) => ReactNode

    The router link for the breadcrumb, the pager, the deal and invoice links; defaults to the LinkProvider's.

  • className
    string

    Merged onto the root.

  • classNames
    Partial<Record<CrmContactPageSlot, string>>

    Classes for the parts: header, tabs, panel, section, aside, archived, dealDialog.

Parts

  • DEFAULT_CRM_CONTACT_PAGE_LABELS

    constant

    Every visible string of the page in English, including the nested labels of the composed items. Spread it and override a few to translate. Type: CrmContactPageLabels.

  • CRM_CONTACT_PAGE_LABELS_EN

    constant

    The same English set under an explicit name, next to the Romanian one.

  • CRM_CONTACT_PAGE_LABELS_RO

    constant

    The ready Romanian set of every string, for the localization demo or a Romanian app.

  • OverviewPanel

    component

    The Overview tab on its own: company details with copy buttons, the contacts, the open deals and the last four events. Takes ctx (CrmPanelContext), company, contacts, primaryContactId, deals, activity, onTabChange and onAddContact.

  • ActivityPanel

    component

    The Activity tab: a comment box with @ mentions, the kind filter chips and the grouped timeline. Takes ctx, activity, people, currentUser, onComment, onAddNote and onAnnounce.

  • DealsPanel

    component

    The Deals tab: a sortable table (cards on phones) with the open total and a New deal button. Takes ctx, deals and onNewDeal.

  • FilesPanel

    component

    The Files tab: a drop zone with upload progress and the file list with preview, download and delete. Takes ctx, files, uploads, onUploadsChange, upload, onDelete, onPreview, onDownload and radius.

  • NotesPanel

    component

    The Notes tab: a rich text editor with mentions and the saved notes with pin, edit and delete. Takes ctx, notes, people, currentUser, noteShortcut, autoFocus, radius, onCreate, onUpdate, onDelete and onAnnounce.

  • toTimelineItem

    function

    Turns a CRM activity into a Timeline item, filling in the icon of its kind. Signature: (item: CrmActivity) => TimelineItemData.

  • stageTone

    function

    The badge tone of a deal stage: success when won, danger when lost, neutral otherwise. Signature: (stage: CrmDealStage | undefined) => Tone.

  • ACTIVITY_ICONS

    constant

    The lucide icon per activity kind (email, call, meeting, invoice, payment, stage, comment, note, file).

  • CRM_CONTACT_SAMPLE

    constant

    Sample data: Tech Solutions Inc. with its contacts, 3 deals, 14 activity items, 6 files and 3 notes. The page's default content.

  • CRM_CONTACT_ARCHIVED_SAMPLE

    constant

    Sample data for an archived record (Westside Books, a former client), shown read-only.

  • CRM_CONTACT_UPLOAD_SAMPLE

    constant

    Sample uploads in progress, for the files example.

  • CRM_CONTACT_TEAM

    constant

    Sample team members with roles, the people you can @mention.

  • CRM_CONTACT_CURRENT_USER

    constant

    The sample signed-in user who writes comments and notes.

  • CRM_CONTACT_STAGES

    constant

    Sample B2B pipeline stages with probabilities: Qualified, Needs analysis, Proposal sent, Negotiation, Won and Lost.

  • CRM_CONTACT_NOW

    constant

    The fixed date the sample data is relative to, so relative times read the same on every render.

  • CrmPanelContext

    type

    What the page hands every tab panel: labels, locale, currency, tone, the section surface class, now, loading, archived, stages and the money, day, relative and percent formatters.

  • CrmContactSample

    type

    { company, contacts, primaryContactId?, deals, activity, files, notes }, the shape of a record's data.

Examples

Open

Activity

defaultTab="activity": the comment composer, the filter chips and 14 events grouped by day. Alt + arrows walk the pager.

Open

Notes, editor focused

defaultTab="notes" with autoFocusNote: write, then press ⌘ Enter to save; pin, edit or delete from ⋯.

Open

Files, one upload running

defaultUploads: Delivery-acceptance-report.pdf finishes uploading and joins the list.

Open

Archived client

Westside Books: the Archived status, the Restore alert and read-only actions.

Open

Loading

loading: the header, the sections, the contact card and the side panel as skeletons.

Open

Brand tone, tiles

tone="brand", radius="lg", factsLayout="tiles", on the deals tab.

Open

Romanian copy, RON

CRM_CONTACT_PAGE_LABELS_RO, locale="ro-RO", currency="RON": the ready Romanian set for the page and its parts.

Dependencies

motionlucide-reactreact-hook-formzodalertavatarbadgebuttoncomment-threadcontact-cardcurrency-inputdate-pickerdescription-listdetail-layoutdialogdropdown-menuempty-stateentity-headerfile-listfile-uploadinputkbdrich-text-editorselecttabletabstagtimelinetoastuse-controllable-stateuse-shortcutcommercedate-utilsform-validationinvoicingmotionnavigationnumber-formatrelative-timetonesui-config

Files

  • components/blocks/crm-contact-page.tsx
  • components/blocks/crm-contact-page-tabs.tsx
  • components/blocks/crm-contact-page-data.ts

FAQ

Is the React CRM Contact Page block free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install CRM Contact Page?

Run npx wingo-ui@latest add crm-contact-page. It also adds the Wingo UI items it builds on (Alert, Avatar, Badge, Button, Comment Thread and 32 more) and the npm packages motion, lucide-react, react-hook-form and zod. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/crm-contact-page.

How does CRM Contact Page behave on phones?

The header shows the company with its status, a star and a follow toggle, key facts (copy the tax ID, open the last invoice) and actions: Email and Call open the mail app and the phone, New deal opens a validated dialog (title, value, stage, close date) and the new deal lands in the deals tab, the rest (New invoice, Add contact, Export record.

See also

CRM Pipeline PageEntity HeaderDetail LayoutContact cardTimelineAdmin Shell

More React blocks

Error PagesInbox PageInvoice PageKPI DashboardListing Detail PageMarketplace Search Page
All 26 React blocks

Articles using this component

  • React CRM Template: Pipeline, Forecast, Company Pages

    Build it: screens and apps · Oct 16, 2026 · 11 min read

PreviousCheckout PageNext CRM Pipeline Page