Table of Contents (TOC)

List of page anchors for the current page.

Usage

Highlight one or more elements of the TOC if in view.

Loading...
'use client'
 
import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react'
import { AnchorProvider, Toc, TOCItems, TOCScrollArea, type AnchorProviderProps } from 'ui-patterns'
 
export function MultiSelectDemo() {
  return (
    <TocAnchorsProvider>
      <div
        id="example-toc-demo"
        className="p-4 md:p-8 grid md:grid-cols-4 gap-4 max-h-[600px] overflow-y-auto"
      >
        <div className="md:col-span-3">
          <div className="prose max-w-none">
            <h1>Getting Started with Cloud Computing</h1>
 
            <h2 id="introduction">
              Introduction
              <a
                href="#introduction"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Cloud computing has revolutionized how we build and deploy applications. This guide
              will walk you through the fundamental concepts and best practices.
            </p>
 
            <h2 id="key-concepts">
              Key Concepts
              <a
                href="#key-concepts"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Before diving deep into cloud services, it&apos;s important to understand the basic
              building blocks that make cloud computing possible.
            </p>
 
            <h3 id="iaas">
              Infrastructure as a Service (IaaS)
              <a
                href="#iaas"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              IaaS provides virtualized computing resources over the internet. This includes virtual
              machines, storage, and networking.
            </p>
 
            <h3 id="paas">
              Platform as a Service (PaaS)
              <a
                href="#paas"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              PaaS delivers a platform allowing customers to develop, run, and manage applications
              without dealing with infrastructure.
            </p>
 
            <h2 id="best-practices">
              Best Practices
              <a
                href="#best-practices"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Following cloud computing best practices ensures optimal performance, security, and
              cost-effectiveness.
            </p>
 
            <h3 id="security">
              Security Considerations
              <a
                href="#security"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              Security should be your top priority when working with cloud services. Implement
              proper authentication, encryption, and access controls.
            </p>
 
            <h3 id="cost-optimization">
              Cost Optimization
              <a
                href="#cost-optimization"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              Learn how to optimize your cloud spending through resource planning, monitoring, and
              implementing cost-saving strategies.
            </p>
 
            <h2 id="conclusion">
              Conclusion
              <a
                href="#conclusion"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Cloud computing continues to evolve, offering new possibilities for businesses and
              developers alike. Stay updated with the latest trends and best practices.
            </p>
          </div>
        </div>
        <TocComponent />
      </div>
    </TocAnchorsProvider>
  )
}
 
const TocComponent = () => {
  const { toc } = useTocAnchors()
 
  return (
    <Toc className="sticky top-0 border-l">
      <h3 className="inline-flex items-center gap-1.5 font-mono text-xs uppercase text-foreground pl-[calc(1.5rem+6px)]">
        On this page
      </h3>
      <TOCScrollArea className="-ml-[2px]">
        <TOCItems items={toc} />
      </TOCScrollArea>
    </Toc>
  )
}
 
interface TOCHeader {
  id?: string
  text: string
  link: string
  level: number
}
 
const TocAnchorsContext = createContext<AnchorProviderProps | undefined>(undefined)
 
const useTocAnchors = () => {
  const context = useContext(TocAnchorsContext)
  if (!context) {
    throw new Error('useTocAnchors must be used within an TocAnchorsContext')
  }
  return context
}
 
const TocAnchorsProvider = ({ children }: PropsWithChildren) => {
  const [tocList, setTocList] = useState<TOCHeader[]>([])
 
  const toc = tocList.map((item) => ({
    title: item.text,
    url: item.link,
    depth: item.level,
  }))
 
  useEffect(() => {
    /**
     * Because we're directly querying the DOM, needs the setTimeout so the DOM
     * update will happen first.
     */
    const timeoutHandle = setTimeout(() => {
      const headings = Array.from(
        document.querySelector('#example-toc-demo')?.querySelectorAll('h2, h3') ?? []
      )
 
      const newHeadings = headings
        .filter((heading) => heading.id)
        .map((heading) => {
          const text = heading?.textContent?.replace('#', '')
          const link = heading.querySelector('a')?.getAttribute('href')
          if (!link) return null
 
          const level = heading.tagName === 'H2' ? 2 : 3
 
          return { text, link, level } as Partial<TOCHeader>
        })
        .filter((x): x is TOCHeader => !!x && !!x.text && !!x.link && !!x.level)
 
      setTocList(newHeadings)
    }, 100)
 
    return () => clearTimeout(timeoutHandle)
    /**
     * window.location.href needed to recalculate toc when page changes,
     * `useSubscribeTocRerender` above will trigger the rerender
     */
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [typeof window !== 'undefined' && window.location.href])
 
  return (
    <TocAnchorsContext.Provider value={{ toc }}>
      <AnchorProvider toc={toc} single={false}>
        {children}
      </AnchorProvider>
    </TocAnchorsContext.Provider>
  )
}

Single=true

Highlight one element of the TOC at a time.

Loading...
'use client'
 
import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react'
import { AnchorProvider, Toc, TOCItems, TOCScrollArea, type AnchorProviderProps } from 'ui-patterns'
 
export function MultiSelectDemo() {
  return (
    <TocAnchorsProvider>
      <div
        id="example-toc-single-demo"
        className="p-4 md:p-8 grid md:grid-cols-4 gap-4 max-h-[600px] overflow-y-auto"
      >
        <div className="md:col-span-3">
          <div className="prose max-w-none">
            <h1>Getting Started with Cloud Computing</h1>
 
            <h2 id="single-introduction">
              Introduction
              <a
                href="#single-introduction"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Cloud computing has revolutionized how we build and deploy applications. This guide
              will walk you through the fundamental concepts and best practices.
            </p>
 
            <h2 id="single-key-concepts">
              Key Concepts
              <a
                href="#single-key-concepts"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Before diving deep into cloud services, it&apos;s important to understand the basic
              building blocks that make cloud computing possible.
            </p>
 
            <h3 id="single-iaas">
              Infrastructure as a Service (IaaS)
              <a
                href="#single-iaas"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              IaaS provides virtualized computing resources over the internet. This includes virtual
              machines, storage, and networking.
            </p>
 
            <h3 id="single-paas">
              Platform as a Service (PaaS)
              <a
                href="#single-paas"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              PaaS delivers a platform allowing customers to develop, run, and manage applications
              without dealing with infrastructure.
            </p>
 
            <h2 id="single-best-practices">
              Best Practices
              <a
                href="#single-best-practices"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Following cloud computing best practices ensures optimal performance, security, and
              cost-effectiveness.
            </p>
 
            <h3 id="single-security">
              Security Considerations
              <a
                href="#single-security"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              Security should be your top priority when working with cloud services. Implement
              proper authentication, encryption, and access controls.
            </p>
 
            <h3 id="single-cost-optimization">
              Cost Optimization
              <a
                href="#single-cost-optimization"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h3>
            <p>
              Learn how to optimize your cloud spending through resource planning, monitoring, and
              implementing cost-saving strategies.
            </p>
 
            <h2 id="single-conclusion">
              Conclusion
              <a
                href="#single-conclusion"
                aria-hidden="true"
                className="ml-2 opacity-0 group-hover:opacity-100 transition"
              >
                <span aria-hidden="true">#</span>
              </a>
            </h2>
            <p>
              Cloud computing continues to evolve, offering new possibilities for businesses and
              developers alike. Stay updated with the latest trends and best practices.
            </p>
          </div>
        </div>
        <TocComponent />
      </div>
    </TocAnchorsProvider>
  )
}
 
const TocComponent = () => {
  const { toc } = useTocAnchors()
 
  return (
    <Toc className="sticky top-0 border-l">
      <h3 className="inline-flex items-center gap-1.5 font-mono text-xs uppercase text-foreground pl-[calc(1.5rem+6px)]">
        On this page
      </h3>
      <TOCScrollArea className="-ml-[2px]">
        <TOCItems items={toc} />
      </TOCScrollArea>
    </Toc>
  )
}
 
interface TOCHeader {
  id?: string
  text: string
  link: string
  level: number
}
 
const TocAnchorsContext = createContext<AnchorProviderProps | undefined>(undefined)
 
const useTocAnchors = () => {
  const context = useContext(TocAnchorsContext)
  if (!context) {
    throw new Error('useTocAnchors must be used within an TocAnchorsContext')
  }
  return context
}
 
const TocAnchorsProvider = ({ children }: PropsWithChildren) => {
  const [tocList, setTocList] = useState<TOCHeader[]>([])
 
  const toc = tocList.map((item) => ({
    title: item.text,
    url: item.link,
    depth: item.level,
  }))
 
  useEffect(() => {
    /**
     * Because we're directly querying the DOM, needs the setTimeout so the DOM
     * update will happen first.
     */
    const timeoutHandle = setTimeout(() => {
      const headings = Array.from(
        document.querySelector('#example-toc-single-demo')?.querySelectorAll('h2, h3') ?? []
      )
 
      const newHeadings = headings
        .filter((heading) => heading.id)
        .map((heading) => {
          const text = heading?.textContent?.replace('#', '')
          const link = heading.querySelector('a')?.getAttribute('href')
          if (!link) return null
 
          const level = heading.tagName === 'H2' ? 2 : 3
 
          return { text, link, level } as Partial<TOCHeader>
        })
        .filter((x): x is TOCHeader => !!x && !!x.text && !!x.link && !!x.level)
 
      setTocList(newHeadings)
    }, 100)
 
    return () => clearTimeout(timeoutHandle)
    /**
     * window.location.href needed to recalculate toc when page changes,
     * `useSubscribeTocRerender` above will trigger the rerender
     */
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [typeof window !== 'undefined' && window.location.href])
 
  return (
    <TocAnchorsContext.Provider value={{ toc }}>
      <AnchorProvider toc={toc} single={true}>
        {children}
      </AnchorProvider>
    </TocAnchorsContext.Provider>
  )
}