Profile
People and organizations: bylines, author blocks, bio rows and team grids, with Avatar portraits.
import {
Profile,
ProfileBio,
ProfileName,
ProfilePortrait,
} from '@fairgarden-private/design/components/Profile'
Names set in the serif and roles in caps sans. Use real portraits or initials, never generic silhouettes, and never overlay a name on a photo. ProfileNameLink links the whole profile (or team member) through a title Link, and the item draws the focus ring; social links in ProfileLinks stay separate tab stops. Former members say so in words, never by dimming. Species use the card and testimonials use Quote.
Byline, author block and bio row
Byline, author block and bio row
kind is required and sets the portrait's Avatar size: 32 px in a byline (with "By Name" and the date joined by "·"), 40 px in an author block, 64 px in a bio row, stepping to 128 px from 768 px of container. The bio row keeps the portrait beside the text, even on phones, and stacks below 360 px of container. Avatars keep their own ring and initials face on every ground.
Ana Díaz
Stewardship director
import { AvatarFallback, AvatarImage } from '@fairgarden-private/design/components/Avatar'
import { Link } from '@fairgarden-private/design/components/Link'
import {
Profile,
ProfileBio,
ProfileDate,
ProfileDetails,
ProfileLinks,
ProfileName,
ProfileNameLink,
ProfilePortrait,
ProfileRole,
} from '@fairgarden-private/design/components/Profile'
import { portrait } from '../portrait'
import styles from './kinds.module.css'
/** The Avatar size follows the kind: byline 32 px, author 40 px, bio 64 px (128 px when wide). */
export function ProfileKinds() {
return (
<div className={styles.stack}>
<Profile kind="byline">
<ProfilePortrait>
<AvatarImage src={portrait} alt="" />
<AvatarFallback>AD</AvatarFallback>
</ProfilePortrait>
<ProfileName>
By <ProfileNameLink href="#kinds">Ana Díaz</ProfileNameLink>
</ProfileName>
<ProfileDate dateTime="2026-09-12">12 Sep 2026</ProfileDate>
</Profile>
<Profile kind="author">
<ProfilePortrait>
<AvatarFallback>HR</AvatarFallback>
</ProfilePortrait>
<ProfileName>Hemlock Ravine Land Trust</ProfileName>
<ProfileBio>
A member-supported land trust caring for 1,200 acres of forest and meadow since 1987.
</ProfileBio>
</Profile>
<Profile kind="bio">
<ProfilePortrait>
<AvatarImage src={portrait} alt="" />
<AvatarFallback>AD</AvatarFallback>
</ProfilePortrait>
<ProfileDetails>
<ProfileName>Ana Díaz</ProfileName>
<ProfileRole>Stewardship director</ProfileRole>
<ProfileBio>
Ana leads the trail crews and the spring bird count. Before the trust she mapped
wetlands for the state and still can’t pass a puddle without checking for eggs.
</ProfileBio>
<ProfileLinks>
<li>
<Link href="#kinds">ana@example.org</Link>
</li>
<li>
<Link href="#kinds">@anadiaz</Link>
</li>
</ProfileLinks>
</ProfileDetails>
</Profile>
</div>
)
}
Team
Team
ProfileTeam lays out ProfileMembers with square ProfileTeamPhotos in a hairline frame: 1-up below 360 px of container, 2-up from 360, 4-up from 768 and up to 5 from 1024. On saturated grounds use only an author block or a single bio row. Team grids print 3-up, photos in grayscale.
Ana Díaz
Stewardship director
Ben Okafor
Trail crew lead
Mei Lin
Education
Sam Reyes
Former board chair
Iris Novak
Development
import {
Profile,
ProfileMember,
ProfileName,
ProfileNameLink,
ProfileRole,
ProfileTeam,
ProfileTeamPhoto,
} from '@fairgarden-private/design/components/Profile'
import { portrait } from '../portrait'
const people = [
{ name: 'Ana Díaz', role: 'Stewardship director' },
{ name: 'Ben Okafor', role: 'Trail crew lead' },
{ name: 'Mei Lin', role: 'Education' },
{ name: 'Sam Reyes', role: 'Former board chair' },
{ name: 'Iris Novak', role: 'Development' },
]
/** Team cells: 1-up below 360 px of container, 2-up from 360, 4-up from 768, up to 5 from 1024. */
export function ProfileTeamDemo() {
return (
<Profile kind="team">
<ProfileTeam>
{people.map((person) => (
<ProfileMember key={person.name}>
<ProfileTeamPhoto src={portrait} alt="" />
<ProfileName>
<ProfileNameLink href="#team">{person.name}</ProfileNameLink>
</ProfileName>
<ProfileRole>{person.role}</ProfileRole>
</ProfileMember>
))}
</ProfileTeam>
</Profile>
)
}
API Reference
Profile
The profile module. A byline holds ProfilePortrait, ProfileName and
ProfileDate; an author block ProfilePortrait, ProfileName,
ProfileBio; a bio row ProfilePortrait and ProfileDetails (name,
role, bio, links); a team ProfileTeam of ProfileMembers, each with a
ProfileTeamPhoto, ProfileName and ProfileRole. Use real portraits
or initials; never overlay names on photos, never dim former members.
| Prop | Type | Description |
|---|---|---|
kind | | Required. |
primary | | Primary Radix scale: rings, frames, initials and text. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: only the name-link and social-link underlines
( |
ProfilePortrait and ProfileTeamPhoto
The portrait: an Avatar sized by the kind (byline 32 px, author 40 px,
bio 64 px stepping to 128 px from 768 px of container), with its ring per
§10.12, taking the module’s primary and secondary unless given its
own. Compose AvatarImage (empty alt where the name is adjacent) and
AvatarFallback (1–2 initials) inside; the fallback keeps the spacing.
| Prop | Type | Description |
|---|---|---|
primary | | Primary Radix scale: the ring. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale, accepted for the shared contract; no part uses it. |
size | |
|
A team member’s photo: a plain img, square at the cell’s full width,
--ds-radius-8, framed in a --border-size-1 --role-hairline line.
Give it empty alt when the name follows.
ProfileName and ProfileNameLink
The name in --primary12: type-itemhead for the author block, bio row
and team, type-body-ui at --font-weight-6 in a byline (“By Name”).
Renders <h3>, or <span> in a byline. Wrap a ProfileNameLink inside
to link the profile.
The profile’s one link, inside ProfileName: a §9.3 title Link whose hit
area stretches over the member (or the whole profile). Hover, focus and
press underline the name; the item draws the focus ring.
| Prop | Type | Description |
|---|---|---|
external | | Adds the arrow-open mark and “(external site)” for assistive technology.
Default |
index | | Adds the screen-only visited ✓ used in long indexes, such as reference
and archive lists. Default |
list | | With |
muted | | Rests in |
primary | | Primary Radix scale: the link text and focus ring. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: the accent underline. Never defaulted; omitted, it inherits the scope. |
className | | Extra class names, added after the module’s own. |
ProfileDetails, ProfileRole, ProfileBio, ProfileLinks and ProfileDate
The bio row’s text column beside the portrait: name, role, bio and links.
Role or affiliation: type-label caps in --primary12. Former members
say so in words (“Former board chair”); never dim them.
A short bio or description, 3–5 lines of type-body-ui in --primary12; prints in full.
Social and contact links, a ul of li > Link: text links with the
--role-accent underline, or inline-tier icons. They sit above a
stretched name link as their own tab stops. In print, write handles in
text; icon-only links are omitted.
The byline date, after a “·” separator: type-caption in --primary12. Pass dateTime.
ProfileTeam and ProfileMember
The team grid: 1-up below 360 px of container, 2-up from 360, 4-up from 768, up to 5-up from 1024 (auto-fit at 152 px without container-query support). Prints 3-up.
One team member: photo → name → role. A ProfileNameLink links the whole cell.
Additional types
ProfileBioProps
Props for ProfileBio: div props and render.
type ProfileBioProps = useRender.ComponentProps<'div'>ProfileDateProps
Props for ProfileDate: time props and render.
type ProfileDateProps = useRender.ComponentProps<'time'>ProfileDetailsProps
Props for ProfileDetails: div props and render.
type ProfileDetailsProps = useRender.ComponentProps<'div'>ProfileKind
The four profile builds (§12.15).
type ProfileKind = 'byline' | 'author' | 'bio' | 'team'ProfileLinksProps
Props for ProfileLinks: list props and render.
type ProfileLinksProps = useRender.ComponentProps<'ul'>ProfileMemberProps
Props for ProfileMember: list-item props and render.
type ProfileMemberProps = useRender.ComponentProps<'li'>ProfileNameLinkProps
Props for ProfileNameLink: Link props except kind, which is always title.
type ProfileNameLinkProps = {
/** Extra class names, added after the module's own. */
className?: string;
/**
* Primary Radix scale: the link text and focus ring. Never defaulted;
* omitted, it inherits the scope [D133].
*/
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
/**
* Secondary Radix scale: the accent underline. Never defaulted; omitted,
* it inherits the scope.
*/
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
/**
* With `kind="nav"`: a list link (nav-panel, footer, drawer and breadcrumb
* lists), whose hover is `--role-link-hover` color only, plus the
* `--ds-stroke-1-5` `--role-accent` underline where that ink is
* `--primary12`. Without it, `nav` is bare navigation text (bar and
* utility items, page numbers, toolbar links), whose hover is the
* `--border-size-2` `--role-accent` underline (§9.3) [D181]. Default
* `false`.
*/
list?: boolean | null;
/**
* Adds the screen-only visited ✓ used in long indexes, such as reference
* and archive lists. Default `false` [D174, D175].
*/
index?: boolean | null;
/**
* Adds the arrow-open mark and "(external site)" for assistive technology.
* Default `false`.
*/
external?: boolean | null;
/**
* Rests in `--role-muted` instead of `--primary12`, as a breadcrumb's
* ancestors. Hover takes `--role-link-hover` only (the underline is added
* where that ink is `--primary12`); with `kind="nav"` it replaces the bar
* item's bare-text underline (§9.3, §9.8) [D181]. Default `false`.
*/
muted?: boolean | null;
}ProfileNameProps
Props for ProfileName: heading props and render (default <h3>; <span> in a byline).
type ProfileNameProps = useRender.ComponentProps<'h3'>ProfilePortraitProps
Props for ProfilePortrait: Avatar props; size follows the kind unless given.
type ProfilePortraitProps = AvatarPropsProfileProps
Props for Profile: div props, render, the kind and the color axes.
type ProfileProps = React.ClassAttributes<HTMLDivElement> &
React.HTMLAttributes<HTMLDivElement> &
__type & {
kind: ProfileKind;
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
}ProfileRoleProps
Props for ProfileRole: paragraph props and render.
type ProfileRoleProps = useRender.ComponentProps<'p'>ProfileTeamPhotoProps
Props for ProfileTeamPhoto: img props and render.
type ProfileTeamPhotoProps = useRender.ComponentProps<'img'>ProfileTeamProps
Props for ProfileTeam: list props and render.
type ProfileTeamProps = useRender.ComponentProps<'ul'>Specification: DESIGN-SYSTEM.md §12.15 (profile and team) and §10.12 (avatar).