# Profile

> An example profile page — avatar, stats, and tabbed content.

A shadcn/ui block from the [@1st-pouf](https://1st-pouf.worksonmy.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/1st-pouf/profile).

- Page, with a live preview: https://shadcn.exchange/r/1st-pouf/profile
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/1st-pouf/profile-light-56b37c38b7990d4d.png
- Registry item: https://1st-pouf.worksonmy.dev/r/profile.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://1st-pouf.worksonmy.dev/r/profile.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://1st-pouf.worksonmy.dev/r/avatar.json`, `https://1st-pouf.worksonmy.dev/r/base.json`, `https://1st-pouf.worksonmy.dev/r/button.json`, `https://1st-pouf.worksonmy.dev/r/disclosure.json`, `https://1st-pouf.worksonmy.dev/r/icon.json`, `https://1st-pouf.worksonmy.dev/r/layout.json`, `https://1st-pouf.worksonmy.dev/r/media.json`, `https://1st-pouf.worksonmy.dev/r/readout.json`, `https://1st-pouf.worksonmy.dev/r/surface.json`, `https://1st-pouf.worksonmy.dev/r/text.json`

## Files

### `registry/pouf/blocks/profile.tsx`

```tsx
import { useState } from 'react'
import { Card } from '../surface'
import { Stack, Row, Grid } from '../layout'
import { Heading, Text, Eyebrow } from '../text'
import { Avatar } from '../avatar'
import { Badge, Dot } from '../media'
import { Metric } from '../readout'
import { Button } from '../Button'
import { Tabs } from '../disclosure'
import { Icon } from '../Icon'

/** An example profile page: header with avatar and stats, a follow button
 * that moves the follower count, and tabbed content. */
export function ProfileBlock() {
  const [tab, setTab] = useState('posts')
  const [following, setFollowing] = useState(false)
  // Derived, not separate state: following IS the +1 follower, so there's
  // nothing to keep in sync — unfollowing can't leave the count stale.
  const followers = 4201 + (following ? 1 : 0)

  const posts = (
    <Stack gap={3}>
      {['Shipped the new cushion buttons', 'Optical centering is a rabbit hole', 'Pastel that passes WCAG — a thread'].map((p, i) => (
        <Card variant="tight" key={i}>
          <Stack gap={2}>
            <Text>{p}</Text>
            <Row gap={4}>
              <Row gap={1} wrap={false}><Icon name="heart" size="sm" /><Text size="sm" muted>{12 * (i + 1)}</Text></Row>
              <Row gap={1} wrap={false}><Icon name="comment" size="sm" /><Text size="sm" muted>{i + 1}</Text></Row>
            </Row>
          </Stack>
        </Card>
      ))}
    </Stack>
  )

  const about = (
    <Stack gap={3}>
      <Text>Designer & engineer. Making software that feels like it wants to be touched. Currently building 1st-Pouf.</Text>
      <Row gap={2}>
        <Badge tone="mint">Design systems</Badge>
        <Badge tone="blue">React</Badge>
        <Badge tone="pink">Motion</Badge>
      </Row>
    </Stack>
  )

  return (
    <div style={{ maxWidth: 640, margin: '0 auto', padding: 24 }}>
      <Card>
        <Stack gap={5}>
          <Row justify="between" align="top">
            <Row gap={3} wrap={false} align="top">
              <Avatar fallback="AL" size="lg" tone="purple" />
              <Stack gap={1}>
                <Heading level={2}>Ada Lovelace</Heading>
                <Eyebrow>@ada</Eyebrow>
                <Row gap={2} wrap={false}>
                  <Dot tone="mint" />
                  <Text size="sm" muted>Active now</Text>
                </Row>
              </Stack>
            </Row>
            <Button tone={following ? 'mint' : 'purple'} variant={following ? 'quiet' : 'solid'} onClick={() => setFollowing((f) => !f)}>
              {following ? 'Following' : 'Follow'}
            </Button>
          </Row>

          <Grid cols={3}>
            <Metric label="Posts" value="128" />
            <Metric label="Followers" value={followers.toLocaleString()} />
            <Metric label="Following" value="312" />
          </Grid>

          <Tabs
            value={tab}
            onChange={setTab}
            tabs={[
              { value: 'posts', label: 'Posts', content: posts },
              { value: 'about', label: 'About', content: about },
            ]}
          />
        </Stack>
      </Card>
    </div>
  )
}
```
