SectionTitle

SectionTitle is the small uppercase eyebrow label cladd uses to break a dense panel into named groups — the line that sits above a cluster of form fields, the heading on a popover section, the divider between unrelated rows in a settings sheet. It renders a <div> with cladd's tuned typography (text-cladd-xs, font-medium, text-cladd-fg-soft, uppercase, non-selectable) and a flex items-end gap-4 layout so you can drop a count chip, a status badge, or an inline action next to the title without any extra wrapper.

It's intentionally minimal — no levels, no sizes, no variants. The point is consistency: every section header across a cladd app reads the same way, so the eye picks them out instantly in information-rich UIs.

Project
acme-marketing
Live

Landing pages, lifecycle emails, and the press kit microsite.

Owner
Anna Whittakeranna@acme
<Surface
  outline
  className="w-80 rounded-3xl"
  contentClassName="flex flex-col gap-8 p-4"
>
  <div className="flex flex-col gap-2">
    <SectionTitle>Project</SectionTitle>
    <div className="flex items-center justify-between">
      <span className="font-medium">acme-marketing</span>
      <Chip color="green">Live</Chip>
    </div>
    <p className="text-cladd-fg-soft">
      Landing pages, lifecycle emails, and the press kit microsite.
    </p>
  </div>
  <div className="flex flex-col gap-2">
    <SectionTitle>Owner</SectionTitle>
    <div className="flex items-center justify-between">
      <span>Anna Whittaker</span>
      <span className="font-mono text-cladd-fg-softer">anna@acme</span>
    </div>
  </div>
</Surface>

Usage

import { SectionTitle } from '@cladd-ui/react';
 
<SectionTitle>Notifications</SectionTitle>;

Drop it ahead of a group of rows, fields, or list items. Pair it with a Surface for a panel layout, with a Popover to label sections inside a dropdown, or with a stack of Input and Switch controls to head a settings group.

The component is flex items-end gap-4, so anything you put alongside the title text — a Chip count, a small inline action — lines up with the baseline of the label automatically. Push extras to the right with ml-auto.

Examples

Inside a popover

SectionTitle is the natural way to organize a multi-group popover — workspace metadata in one section, notification toggles in another, without falling back to ad-hoc headings or extra dividers. Add contentClassName="p-4" to Popover to give the sections breathing room (the popover surface ships unpadded so List-style content can sit flush with the edge), then stack groups with a flex flex-col gap-6 wrapper.

<PopoverRoot open={open} onOpenChange={setOpen}>
  <PopoverTrigger>
    <Button>Workspace settings</Button>
  </PopoverTrigger>
  <Popover className="w-72" offset={8} contentClassName="p-4 text-sm">
    <div className="flex flex-col gap-6">
      <div className="flex flex-col gap-2">
        <SectionTitle>Workspace</SectionTitle>
        <div className="flex items-center justify-between">
          <span className="font-medium">acme-marketing</span>
          <Chip color="brand">Pro</Chip>
        </div>
        <span className="text-cladd-fg-soft">
          8 members · 42 projects
        </span>
      </div>
      <div className="flex flex-col gap-2">
        <SectionTitle>Notifications</SectionTitle>
        <label className="flex items-center justify-between gap-4">
          <span>Email updates</span>
          <Switch as="div" checked={notify} onChange={setNotify} />
        </label>
        <label className="flex items-center justify-between gap-4">
          <span>Mentions</span>
          <Switch as="div" checked={mentions} onChange={setMentions} />
        </label>
        <label className="flex items-center justify-between gap-4">
          <span>Weekly digest</span>
          <Switch as="div" checked={digest} onChange={setDigest} />
        </label>
      </div>
    </div>
  </Popover>
</PopoverRoot>

Grouped form fields

In a settings sheet, SectionTitle is what tells the eye where one group of fields ends and the next begins. The uppercase eyebrow reads as structural rather than as another field label, so it doesn't fight with the Input labels or Switch rows below it. Wrap each group in a flex flex-col gap-2 container and separate groups with the parent's gap-8 — the rhythm stays predictable even as fields are added or removed.

General
cladd.io/
Publishing
<Surface
  outline
  className="w-96 rounded-3xl"
  contentClassName="flex flex-col gap-8 p-4"
>
  <div className="flex flex-col gap-2">
    <SectionTitle>General</SectionTitle>
    <Input
      value={name}
      onChange={setName}
      placeholder="Project name"
      size="lg"
    />
    <Input
      value={slug}
      onChange={setSlug}
      placeholder="URL slug"
      inputClassName="pl-1"
      prefix={
        <span className="ml-2 text-xs text-cladd-fg-softer">
          cladd.io/
        </span>
      }
      size="lg"
    />
  </div>
  <div className="flex flex-col gap-2">
    <SectionTitle>Publishing</SectionTitle>
    <Input
      value={domain}
      onChange={setDomain}
      placeholder="Custom domain"
      size="lg"
    />
    <label className="flex items-center justify-between gap-4 pt-2">
      <div className="flex flex-col">
        <span>Analytics</span>
        <span className="text-cladd-fg-soft">
          Track page views and referrers
        </span>
      </div>
      <Switch checked={analytics} onChange={setAnalytics} />
    </label>
    <label className="flex items-center justify-between gap-4 pt-2">
      <div className="flex flex-col">
        <span>Search indexing</span>
        <span className="text-cladd-fg-soft">
          Allow search engines to crawl
        </span>
      </div>
      <Switch checked={indexing} onChange={setIndexing} />
    </label>
  </div>
</Surface>

Rich content surface

When a Surface carries more than one kind of content — a header block, a quick-action row, an activity feed — SectionTitle is what holds the structure together. Each section gets a one-line label and the surface's own padding does the spacing. This is the cladd-app pattern: dense, multi-section panels that stay legible because the section headers are consistent and quiet.

Overview
Synced
acme-marketingv2.4.1

Landing pages, lifecycle emails, and the press kit microsite. Last deploy 14 minutes ago.

marketing
nextjs
mdx
Recent activity
Deployed v2.4.114m
Anna merged "lifecycle-emails"2h
Press kit page published1d
<Surface
  outline
  className="w-[28rem] rounded-3xl"
  contentClassName="flex flex-col gap-8 p-4"
>
  <div className="flex flex-col gap-2">
    <SectionTitle>
      <span>Overview</span>
      <Chip color="green" className="ml-auto normal-case">
        Synced
      </Chip>
    </SectionTitle>
    <div className="flex items-baseline justify-between gap-4">
      <span className="text-lg font-semibold">acme-marketing</span>
      <span className="font-mono text-cladd-fg-softer">v2.4.1</span>
    </div>
    <p className="text-cladd-fg-soft">
      Landing pages, lifecycle emails, and the press kit microsite. Last
      deploy 14 minutes ago.
    </p>
    <div className="flex flex-wrap gap-1 pt-1">
      <Chip color="brand">marketing</Chip>
      <Chip color="cyan">nextjs</Chip>
      <Chip color="purple">mdx</Chip>
    </div>
  </div>

  <div className="flex flex-col gap-2">
    <SectionTitle>
      <span>Recent activity</span>
      <button
        type="button"
        className="ml-auto cursor-pointer text-cladd-primary normal-case hover:underline"
      >
        View all
      </button>
    </SectionTitle>
    <List className="-mx-4">
      <ListItem>
        <span className="text-sm">Deployed v2.4.1</span>
        <span className="ml-auto font-mono text-cladd-fg-softer">
          14m
        </span>
      </ListItem>
      <ListSeparator />
      <ListItem>
        <span className="text-sm">Anna merged "lifecycle-emails"</span>
        <span className="ml-auto font-mono text-cladd-fg-softer">2h</span>
      </ListItem>
      <ListSeparator />
      <ListItem>
        <span className="text-sm">Press kit page published</span>
        <span className="ml-auto font-mono text-cladd-fg-softer">1d</span>
      </ListItem>
    </List>
  </div>
</Surface>

End slot

Because the root is flex items-end gap-4, anything passed as a child sits inline with the title. Drop a Chip count next to the label, or push an action to the right with ml-auto. The container's items-end alignment keeps the extras anchored to the baseline of the uppercase label — small chips and short text sit cleanly without per-element tweaking.

The title's uppercase cascades to children, so add normal-case on any nested element (a "View all" link, a status chip) that should render mixed-case.

Members
8
Anna Whittaker
Owner
Jamie Park
Editor
Riley Chen
Viewer
<Surface
  outline
  className="w-96 rounded-3xl"
  contentClassName="flex flex-col gap-2 p-4"
>
  <SectionTitle>
    <span>Members</span>
    <Chip color="brand">8</Chip>
    <button
      type="button"
      className="ml-auto cursor-pointer text-cladd-primary normal-case hover:underline"
    >
      Invite
    </button>
  </SectionTitle>
  <div className="mt-4 flex items-center justify-between">
    <span>Anna Whittaker</span>
    <Chip color="brand">Owner</Chip>
  </div>
  <div className="flex items-center justify-between">
    <span>Jamie Park</span>
    <Chip>Editor</Chip>
  </div>
  <div className="flex items-center justify-between">
    <span>Riley Chen</span>
    <Chip>Viewer</Chip>
  </div>
</Surface>

API Reference

children: ReactNodeTitle content (typically a short uppercase section label).
className: stringExtra classes for the section title root.