Skip to content
Tier

Heading scope

Pro

Says the content inside sits under a heading of level, so each Candor item in it draws its heading one level below (level + 1) unless it is given headingLevel. Put it round a section the app titles itself:

<section aria-labelledby="usage">
  <h2 id="usage">Usage</h2>
  <HeadingScope level={2}>
    <DetailsList … />   // draws its title as <h3>
  </HeadingScope>
</section>

Candor's dialogs, sheets, drawers, settings sections and dashboard tiles set one round their content themselves. A scope inside another replaces it; it doesn't add to it.

Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0, 2.8.0, 2.9.0, 2.10.0, 3.0.0, 4.0.0, 4.0.1, 4.0.2, 4.1.0, 4.2.0, 4.3.0, 4.4.0 and 4.5.0: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/heading-scope

Brings in: heading-level, tokens

Usage

TSX · The example above
"use client"

import type { HeadingLevel } from "@/lib/candor/heading-level"
import { HeadingScope, belowLevel, useHeadingLevel } from "@/lib/candor/heading-scope"
import { Heading } from "@/components/candor/heading"

/** A card as Candor's items draw one: its title at the level the scope gives, its sections one below. */
function UsageCard({ title, sections, headingLevel }: { title: string; sections: string[]; headingLevel?: HeadingLevel | undefined }) {
  const level = useHeadingLevel(headingLevel)
  return (
    <div className="flex flex-col gap-2 rounded-lg border p-4">
      <Heading level={level} size="base">
        {title} <span className="font-normal text-muted-foreground">(h{level})</span>
      </Heading>
      {sections.map((s) => (
        <Heading key={s} level={belowLevel(level)} size="sm">
          {s} <span className="font-normal text-muted-foreground">(h{belowLevel(level)})</span>
        </Heading>
      ))}
    </div>
  )
}

export default function Example() {
  return (
    <section aria-labelledby="usage-heading" className="flex flex-col gap-3">
      <Heading id="usage-heading" level={2} size="lg">
        Usage <span className="font-normal text-muted-foreground">(h2)</span>
      </Heading>
      <HeadingScope level={2}>
        <div className="grid gap-3 sm:grid-cols-2">
          <UsageCard title="This month" sections={["Runs", "Spend"]} />
          <UsageCard title="Last month" sections={["Runs", "Spend"]} />
        </div>
      </HeadingScope>
    </section>
  )
}

<HeadingScope>

PropTypeDefaultDescription
levelrequiredHeadingLevel—The level of the heading the content sits under: `2` when the section's own heading is an `<h2>`.
childrenReact.ReactNode | undefined—The content under that heading.

Functions

useHeadingLevel(headingLevel?: HeadingLevel | undefined)

The level an item draws its top heading at: headingLevel when given; else one below the nearest HeadingScope; else 2. Never deeper than 6.

function Summary({ title, headingLevel }: { title: string; headingLevel?: HeadingLevel | undefined }) {
  const level = useHeadingLevel(headingLevel)
  const Tag = `h${level}` as const
  return <Tag className="text-base font-semibold">{title}</Tag>
}
useHeadingScope()

The level of the nearest HeadingScope, or undefined outside any. For an item that drew no heading in a release before it read the scope, and so becomes a heading only inside one (or when given headingLevel), keeping what it drew outside.

belowLevel(level: HeadingLevel, n: number = 1)

The level n steps below level (one by default), for the headings an item draws under its own top heading. Never deeper than 6. belowLevel(useHeadingLevel(headingLevel)) is the level of a card's title inside a list.

Types from other items

The props above take these. Each is defined by another item; import it from the path shown.

HeadingLevel from @/lib/candor/heading-level
A heading's level in the page's outline: `1` is `<h1>`, `6` is `<h6>`. Every Candor item that draws a heading takes its `headingLevel` as this type; the level is where the heading sits in the outline, never how large it looks.
1 | 2 | 3 | 4 | 5 | 6