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

Profile Page

Blocks

Profile Page React block for Tailwind CSS v4

Pricing PageRegister Page
Live props
State
isOwner
defaultTab
defaultFollowing
defaultEditOpen
loading
Layout
pinnedCount
recentCount
showHeatmap
Appearance
heatmapColor
tone
radius
Behavior
swipeable
animateIn
locale
Code
import { ProfilePage } from "@/components/blocks/profile-page"

<ProfilePage />
  1. Home
  2. Components
  3. Blocks
  4. Profile Page
Pro

Profile Page React block for Tailwind CSS v4

v1.0.0·Added in 1.14.0

A React user profile screen: cover band, avatar with presence, bio and links, follow and message, counters, tabs and an edit profile sheet.

The header shows the cover band, the avatar with a presence dot (online, away, busy, or "Seen 2 hours ago" while offline), the name with a verified mark, the handle, a headline, the bio, the location, links that open in a new tab and the join date. Follow flips to Following at once with a popping check and adds one to Followers; if onFollow rejects it flips back and a screen reader hears why. Message calls onMessage. The Projects counter opens the Projects tab; Followers and Following are buttons when onStatClick is set. Three tabs (arrow keys move between them, Home and End jump): Overview with the pinned project cards, a year of contributions as a heatmap (hover or focus a day for its count) and the latest activity with View all; Projects with every project as a link card (language, stars, last update, a Private badge); Activity as a timeline grouped by day. On the owner's profile Edit profile opens a sheet from the right (a bottom sheet with a drag handle on phones): change the photo (crop, upload progress, remove), the name, the username, a bio with a 160 character counter, the location and the website. Save checks the fields first: a missing name, a username that is not 3 to 20 letters, numbers or underscores, or a website that is not an address turn red and the first one takes focus; the messages then follow your typing. While onSave runs, Save shows a spinner and the sheet stays open; a rejection keeps the draft and shows its message, a success updates the header and closes the sheet. Escape or Cancel closes without saving. On phones the header stacks, the counters become a row of three tiles, the actions fill the width, and the tab pages follow a horizontal swipe.

Profile 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 profile-page, together with Avatar, Avatar Upload, Badge, Button, Card and 14 more and the npm packages motion and lucide-react.

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 profile-page

Profile 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 ProfilePage from @/components/blocks/profile-page.

// app/(app)/u/[handle]/page.tsx
"use client"

import { ProfilePage } from "@/components/blocks/profile-page"
import { PROFILE_PAGE_SAMPLE } from "@/components/blocks/profile-page-data"

export default function ProfileRoute() {
  return (
    <ProfilePage
      user={PROFILE_PAGE_SAMPLE.user}
      projects={PROFILE_PAGE_SAMPLE.projects}
      isOwner
      onFollow={async (following) => {
        await fetch("/api/follow", { method: following ? "POST" : "DELETE" })
      }}
      onSave={async (values) => {
        const res = await fetch("/api/profile", { method: "PUT", body: JSON.stringify(values) })
        if (!res.ok) throw new Error("We could not save your profile. Try again.")
      }}
    />
  )
}

Props

  • userdefault "PROFILE_PAGE_SAMPLE.user"
    ProfileUser

    The person: { id, name, handle, avatar?, cover?, coverColor?, headline?, bio?, location?, website?, links?, joinedAt?, status?, lastSeen?, verified?, followers, following, projectCount?, isFollowing? }. Default: Emma Carter (PROFILE_PAGE_SAMPLE.user).

  • projectsdefault "PROFILE_PAGE_SAMPLE.projects"
    ProfileProject[]

    Project cards: { id, name, description?, href?, language?, languageColor?, stars?, updatedAt?, pinned?, visibility? }. Default: six sample projects.

  • activitydefault "PROFILE_PAGE_SAMPLE.activity"
    ProfileActivity[]

    Timeline rows: { id, type: commit | release | comment | star | project | follow | review, title, description?, time, href? }.

  • contributionsdefault "PROFILE_PAGE_SAMPLE.contributions"
    ProfileContribution[]

    A year of { date, count, level } days for the heatmap, starting on a Sunday; [] hides it. Default: a seeded sample year.

  • isOwnerdefault false
    boolean

    The viewer's own profile: Edit profile replaces Follow and Message.

  • tab
    "overview" | "projects" | "activity"

    The open tab, controlled; pair it with onTabChange (a route per tab).

  • defaultTabdefault "overview"
    "overview" | "projects" | "activity"

    The tab open on mount.

  • onTabChange
    (tab: ProfileTab) => void

    Called when another tab opens, by a press, the keyboard, a swipe or the Projects counter.

  • following
    boolean

    Whether the viewer follows this person, controlled; pair it with onFollow.

  • defaultFollowingdefault false
    boolean

    Following on mount while uncontrolled; user.isFollowing turns it on too.

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

    Runs after Follow flips (optimistic); a rejection flips it back and announces labels.followFailed.

  • onMessage
    () => void

    Adds a Message button next to Follow.

  • onStatClick
    (stat: "followers" | "following") => void

    Turns the Followers and Following counters into buttons (open a list, a route). The Projects counter always opens the Projects tab.

  • editOpen
    boolean

    The edit sheet, controlled; pair it with onEditOpenChange. Every opening starts from the current profile.

  • defaultEditOpendefault false
    boolean

    Opens the edit sheet on mount.

  • onEditOpenChange
    (open: boolean) => void

    Called when the edit sheet opens or closes.

  • onSave
    (values: ProfileDraft) => void | Promise<unknown>

    Saves { name, handle, bio, location, website, avatar } after the checks pass (website with https:// added). A promise keeps Save loading; a rejection keeps the sheet open with its message.

  • onAvatarUpload
    (blob: Blob, context: { file; signal; onProgress }) => Promise<string | void>

    Uploads the cropped photo from the edit sheet; resolve the new url. Without it the photo is a local preview until Save.

  • pinnedCountdefault 4
    number

    Project cards on Overview: pinned ones first, then the rest in order; 0 hides the section.

  • recentCountdefault 3
    number

    Activity rows on Overview, newest first; 0 hides the section.

  • showHeatmapdefault true
    boolean

    The contributions heatmap on Overview.

  • heatmapColordefault "#39d353"
    string

    Any CSS color for the heatmap cells; busier days are more opaque.

  • swipeabledefault true
    boolean

    Below 768px the tab pages follow a horizontal swipe.

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

    Follow, Save and the tab indicator.

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

    Corner size of the header, the cards and the panels (12 / 16 / 24px).

  • loadingdefault false
    boolean

    Skeletons in the real layout while the profile loads.

  • animateIndefault true
    boolean

    The header parts rise in one after another when the page mounts on the client; never while hydrating or under reduced motion.

  • localedefault ""
    string

    Intl locale for the counters, the join date and relative times. Empty falls back to the UIProvider locale, then en-US (the demo offers en-GB, de-DE and ro-RO).

  • now
    Date | number

    The reference time for "Updated 5 hours ago", "Seen 2 hours ago" and the activity times; default the live clock.

  • labels
    Partial<ProfilePageLabels>

    Every visible string, merged over the English DEFAULT_PROFILE_PAGE_LABELS; avatarUpload carries the photo picker's strings.

  • className
    string

    Classes for the root.

  • classNames
    Partial<Record<"header" | "cover" | "avatar" | "identity" | "name" | "bio" | "meta" | "stats" | "stat" | "actions" | "tabs" | "overview" | "projects" | "activity" | "projectCard" | "heatmap" | "timeline" | "sheet", string>>

    Classes for the inner parts.

Parts

  • DEFAULT_PROFILE_PAGE_LABELS

    constant

    Every English string of the page. Spread it and override what you translate.

  • PROFILE_PAGE_SAMPLE

    constant

    The demo data the page renders without props: { user, projects, activity, contributions }.

  • PROFILE_SAMPLE_USER

    constant

    Emma Carter, a design engineer in Brooklyn, New York, online, with 1,284 followers.

  • PROFILE_SAMPLE_PROJECTS

    constant

    Six projects, four of them pinned, one private.

  • PROFILE_SAMPLE_ACTIVITY

    constant

    Seven activity rows: a release, commits, a review, a star, a comment, a new project and a follow.

  • PROFILE_SAMPLE_CONTRIBUTIONS

    constant

    A seeded year of contribution days ending on PROFILE_PAGE_NOW.

  • PROFILE_PAGE_NOW

    constant

    The fixed clock of the sample (Nov 5, 2026, 2:40 PM UTC); pass it as now so screenshots never drift.

  • generateContributions

    function

    Seeded demo contribution days, the same on every render. For demos and tests; pass your real calendar in production.

    • enddefault "PROFILE_PAGE_NOW"
      Date | number

      The last day.

    • weeksdefault 53
      number

      How many weeks back, rounded to a Sunday.

    • seeddefault 2026
      number

      The random seed; the same seed gives the same days.

    • returns
      ProfileContribution[]

      The days, oldest first.

  • ProfileUser

    type

    The person shown in the header.

  • ProfileProject

    type

    One project card.

  • ProfileActivity

    type

    One activity row.

  • ProfileContribution

    type

    One heatmap day: { date: "2026-11-05", count, level: 0 to 4 }.

  • ProfileDraft

    type

    What onSave receives: { name, handle, bio, location, website, avatar }.

  • ProfilePageLabels

    type

    The shape of labels.

Examples

Open

Your own profile

isOwner swaps Follow for Edit profile; save to see the header update.

Open

Edit sheet open

Photo, name, username, bio, location and website, checked on Save. A bottom sheet on phones.

Open

Save that fails

onSave rejects once: the sheet stays open with the message and the draft.

Open

Offline, photo cover, brand

A cover photo, Seen 2 hours ago, 18.4K followers and the brand tone.

Open

New member

No projects, activity or heatmap yet: empty states instead of blank space.

Open

Follow that fails

Follow flips at once and flips back when onFollow rejects.

Open

Projects tab, large corners

defaultTab="projects" with radius="lg".

Open

Loading

Skeletons in the real layout.

Dependencies

motionlucide-reactavataravatar-uploadbadgebuttoncardgithub-activityinputpresencesheetswipeable-tabstextareatimelineuse-controllable-stateuse-media-querymotionnumber-formatrelative-timetonesui-config

Files

  • components/blocks/profile-page.tsx
  • components/blocks/profile-page-data.ts

FAQ

Is the React Profile Page block free?

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

How do I install Profile Page?

Run npx wingo-ui@latest add profile-page. It also adds the Wingo UI items it builds on (Avatar, Avatar Upload, Badge, Button, Card and 14 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/profile-page.

How does Profile Page behave on phones?

On the owner's profile Edit profile opens a sheet from the right (a bottom sheet with a drag handle on phones): change the photo (crop, upload progress, remove), the name, the username, a bio with a 160 character counter, the location and the website.

See also

Settings PageAvatar UploadGitHub ActivitySwipeable TabsTimeline

More React blocks

Register PageUsers Admin PageOnboarding FlowLogin PageMarketplace Home PageMobile App Home
All 26 React blocks

Articles using this component

  • Shadcn Profile Page in React: Follow, Tabs and Edit Sheet

    Build it: screens and apps · Nov 6, 2026 · 9 min read

PreviousPricing PageNext Register Page