Profile
User profile view component
Profile
The Profile view displays and manages user profile information including personal details, avatar, bio, activity history, and user statistics. It supports both viewing and editing modes.
Type Signature
interface ProfileViewProps {
/** Page title */
title?: string
/** Page description */
description?: string
/** View layout mode */
layout?: 'single' | 'column' | 'canvas' | 'vibe'
/** User profile data */
user?: {
id: string
name: string
email: string
avatar?: string
bio?: string
role?: string
metadata?: Record<string, any>
}
/** Editable mode */
editable?: boolean
/** Show activity feed */
showActivity?: boolean
/** Show stats/metrics */
showStats?: boolean
/** Page-level action buttons */
actions?: Array<{
id: string
label: string
icon?: string
onClick?: () => void
variant?: 'default' | 'primary' | 'destructive'
}>
/** Loading state */
loading?: boolean
/** Error state */
error?: string
/** Child content */
children?: React.ReactNode
}Usage
<App name="Acme Dashboard">
<Shell>
<ProfileView
user={{
id: '1',
name: 'Jane Doe',
email: 'jane@acme.com',
avatar: 'https://avatar.url/jane',
bio: 'Product Designer at Acme',
role: 'admin'
}}
editable={true}
showActivity={true}
showStats={true}
/>
</Shell>
</App>Props
title
The page title displayed in the header. Defaults to "Profile".
<ProfileView title="My Profile">description
Optional page description.
<ProfileView
title="Profile"
description="Manage your personal information and preferences"
>layout
Layout mode for the profile content. Defaults to 'single'.
// Single column layout (default)
<ProfileView layout="single">
// Multi-column layout
<ProfileView layout="column">user
User profile data to display.
<ProfileView
user={{
id: 'user_123',
name: 'Jane Doe',
email: 'jane.doe@acme.com',
avatar: 'https://avatar.url/jane',
bio: 'Product Designer passionate about creating delightful user experiences',
role: 'Team Lead',
metadata: {
location: 'San Francisco, CA',
website: 'https://janedoe.com',
twitter: '@janedoe',
joinedAt: '2023-01-15'
}
}}
/>editable
Enable profile editing mode. Defaults to false.
// View-only mode (default)
<ProfileView
user={user}
editable={false}
/>
// Editable mode
<ProfileView
user={user}
editable={true}
onSave={handleSave}
/>showActivity
Display recent activity feed. Defaults to true.
<ProfileView
user={user}
showActivity={true}
>
{/* Shows recent user activity */}
</ProfileView>showStats
Display user statistics and metrics. Defaults to true.
<ProfileView
user={user}
showStats={true}
>
{/* Shows activity stats, contributions, etc. */}
</ProfileView>actions
Page-level action buttons.
<ProfileView
user={user}
actions={[
{
id: 'edit',
label: 'Edit Profile',
icon: 'Edit',
onClick: () => setEditable(true)
},
{
id: 'share',
label: 'Share',
icon: 'Share',
onClick: () => shareProfile()
}
]}
/>Layout Patterns
View Mode
Read-only profile display:
┌─────────────────────────────────────┐
│ [Avatar] Jane Doe │
│ jane@acme.com │
│ Product Designer │
├─────────────────────────────────────┤
│ Bio │
│ Product Designer passionate about │
│ creating delightful UX... │
├──────────────┬──────────────────────┤
│ Stats │ Recent Activity │
│ • 234 Posts │ • Updated profile │
│ • 45 Likes │ • Commented on ... │
└──────────────┴──────────────────────┘Edit Mode
Editable profile form:
┌─────────────────────────────────────┐
│ [Avatar Upload] │
│ Change Avatar │
├─────────────────────────────────────┤
│ Name: [Jane Doe________] │
│ Email: [jane@acme.com__] │
│ Role: [Product Designer] │
│ Bio: [________________] │
│ [________________] │
├─────────────────────────────────────┤
│ [Save Changes] [Cancel] │
└─────────────────────────────────────┘Common Patterns
Basic Profile Display
Simple profile with essential information:
<ProfileView
user={{
name: 'Jane Doe',
email: 'jane@acme.com',
avatar: avatarUrl,
role: 'Product Designer'
}}
showActivity={false}
showStats={false}
/>Profile with Activity
Include activity timeline:
<ProfileView
user={user}
showActivity={true}
>
<ActivityFeed
items={[
{
id: '1',
type: 'comment',
content: 'Commented on "New Feature"',
timestamp: '2 hours ago'
},
{
id: '2',
type: 'update',
content: 'Updated profile picture',
timestamp: '1 day ago'
}
]}
/>
</ProfileView>Profile with Stats
Show user metrics and statistics:
<ProfileView
user={user}
showStats={true}
>
<ProfileStats
stats={[
{ label: 'Posts', value: 234 },
{ label: 'Followers', value: 1250 },
{ label: 'Following', value: 320 }
]}
/>
</ProfileView>Editable Profile
Allow users to edit their profile:
const [isEditing, setIsEditing] = useState(false)
const [profileData, setProfileData] = useState(user)
const handleSave = async (updates: UserProfile) => {
await updateProfile(updates)
setIsEditing(false)
}
<ProfileView
user={profileData}
editable={isEditing}
onSave={handleSave}
actions={[
{
id: 'edit',
label: isEditing ? 'Cancel' : 'Edit Profile',
onClick: () => setIsEditing(!isEditing)
}
]}
/>Profile Sections
Header Section
Avatar, name, and basic info:
<ProfileHeader
avatar={user.avatar}
name={user.name}
email={user.email}
role={user.role}
editable={editable}
/>Bio Section
User biography or description:
<ProfileBio
bio={user.bio}
editable={editable}
onUpdate={handleBioUpdate}
/>Stats Section
User metrics and achievements:
<ProfileStats
stats={{
posts: 234,
followers: 1250,
following: 320,
joined: '2023-01-15'
}}
/>Activity Section
Recent user activity:
<ProfileActivity
activities={recentActivity}
limit={10}
showMore={true}
/>Metadata Section
Additional profile fields:
<ProfileMetadata
metadata={{
location: 'San Francisco, CA',
website: 'https://janedoe.com',
twitter: '@janedoe',
linkedin: 'jane-doe'
}}
editable={editable}
/>Avatar Management
Handle avatar uploads and changes:
const handleAvatarUpload = async (file: File) => {
const url = await uploadAvatar(file)
await updateProfile({ avatar: url })
}
<ProfileView
user={user}
editable={true}
>
<AvatarUpload
current={user.avatar}
onUpload={handleAvatarUpload}
maxSize={5 * 1024 * 1024} // 5MB
accept="image/*"
/>
</ProfileView>App Type Specializations
DeveloperApp Profile
Focus on technical information:
<ProfileView
user={user}
showStats={true}
>
<DeveloperStats
stats={{
apiCalls: '1.2M',
activeKeys: 3,
repositories: 12
}}
/>
<RecentAPIActivity />
</ProfileView>SaaSApp Profile
Show subscription and team info:
<ProfileView
user={user}
>
<SubscriptionBadge plan="Pro" />
<TeamMemberships teams={userTeams} />
<BillingInfo />
</ProfileView>CRMApp Profile
Display sales metrics:
<ProfileView
user={user}
showStats={true}
>
<SalesStats
stats={{
dealsWon: 45,
totalRevenue: '$1.2M',
winRate: '65%'
}}
/>
<RecentDeals />
</ProfileView>Form Validation
Validate profile updates:
const profileSchema = z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
bio: z.string().max(500, 'Bio must be less than 500 characters').optional(),
website: z.string().url().optional()
})
<ProfileView
user={user}
editable={true}
>
<Form
schema={profileSchema}
onSubmit={handleSave}
onError={handleError}
>
{/* Form fields */}
</Form>
</ProfileView>Privacy Controls
Manage profile visibility:
<ProfileView user={user} editable={true}>
<PrivacySettings
options={[
{
field: 'email',
label: 'Email Address',
visibility: 'private' | 'team' | 'public'
},
{
field: 'bio',
label: 'Biography',
visibility: 'public'
}
]}
/>
</ProfileView>Responsive Behavior
Profile adapts to screen size:
Desktop (≥1024px)
┌────────────────────────────────────┐
│ [Avatar] Jane Doe │
│ jane@acme.com │
├────────────┬───────────────────────┤
│ Bio │ Recent Activity │
│ Stats │ • Commented on... │
│ │ • Updated... │
└────────────┴───────────────────────┘Mobile (under 1024px)
┌────────────────────────┐
│ [Avatar] │
│ Jane Doe │
│ jane@acme.com │
├────────────────────────┤
│ Bio │
├────────────────────────┤
│ Stats │
├────────────────────────┤
│ Recent Activity │
│ • Commented on... │
│ • Updated... │
└────────────────────────┘Integration with Payload CMS
Profile can auto-wire to Payload's users collection:
// Auto-fetches current user from Payload
<ProfileView collection="users">
<ProfileContent />
</ProfileView>
// View specific user profile
<ProfileView collection="users" documentId={userId}>
<ProfileContent />
</ProfileView>Best Practices
Use Current User by Default
Load the authenticated user's profile:
// Good - uses current user
<ProfileView user={currentUser}>
// Bad - requires manual user ID
<ProfileView userId="123">Validate Before Save
Always validate profile updates:
const handleSave = async (updates: UserProfile) => {
try {
await profileSchema.parseAsync(updates)
await updateProfile(updates)
toast.success('Profile updated')
} catch (error) {
toast.error('Invalid profile data')
}
}Show Loading States
Display skeletons while loading:
<ProfileView loading={isLoading}>
{isLoading ? (
<ProfileSkeleton />
) : (
<ProfileContent user={user} />
)}
</ProfileView>Handle Missing Avatars
Provide fallback for missing avatars:
<Avatar
src={user.avatar}
fallback={user.name.charAt(0)}
alt={user.name}
/>Accessibility
Profile views implement accessibility features:
- Semantic HTML - Use proper heading hierarchy
- Image alt text - Descriptive avatar alt text
- Form labels - All inputs properly labeled
- Keyboard navigation - Tab through editable fields
<ProfileView
user={user}
aria-label="User profile"
>
<section aria-labelledby="profile-heading">
<h1 id="profile-heading" className="sr-only">
Profile for {user.name}
</h1>
<img
src={user.avatar}
alt={`Profile picture for ${user.name}`}
/>
<div aria-label="User information">
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
</section>
</ProfileView>