---
title: Docs
description: A help center reader with a contents tree, outline, and ⌘K search.
category: TemplateContent
status: beta
since: 0.6.0
tags: [template, docs, markdown, outline, search]
syncStatus: reviewed
verified: false
---

## Usage

### Three-pane docs
:::TuffDemoWrapper{demo="TemplateDocsDemo" code-lang="vue" description="Once in view the article scrolls itself to two sections and stops when you touch it; ⌘K searches articles and sections."}
---
code: |
  <script setup lang="ts">
  import { useIndicatorBox } from '@talex-touch/tuffex/sidebar-nav'
  import { computed, ref } from 'vue'
  import TemplateFrame from './TemplateFrame.vue'

  // The outline is parsed from the markdown source and matched to the rendered
  // h2 / h3 by position: TxMarkdownView headings have no id, and must not get
  // one (the docs page collects id'd headings and scrolls the whole page)
  const outline = computed(() => parseHeadings(article.value.body))

  // Only the article's own scroller moves; never scrollIntoView
  function scrollToHeading(index: number) {
    scroller.value?.scrollTo({ top: offsets[index] - 12, behavior: 'smooth' })
  }

  // Links in the body are real <a>: one delegated handler, #kb:<id> opens an article
  function onBodyClick(event: MouseEvent) {
    const link = (event.target as Element).closest('a')
    if (!link)
      return
    event.preventDefault()
    const href = link.getAttribute('href') ?? ''
    if (href.startsWith('#kb:'))
      openArticle(href.slice(4))
  }

  // The outline marker slides with the same measurement TxSidebarNav uses
  const { box } = useIndicatorBox({ container: outlineList, target: () => items[active.value] })
  </script>

  <template>
    <TemplateFrame title="Three-pane docs" :height="580" @enter="startTour">
      <aside>
        <TxSearchInput v-model="filter" placeholder="Filter contents" />
        <TxTree :nodes="tree" :model-value="articleId" v-model:expanded-keys="open" :filter-text="filter" @select="onTreeSelect" />
      </aside>

      <div ref="scroller" class="article" tabindex="0" @scroll.passive="syncActive">
        <TxBreadcrumb :items="crumbs" @click="onCrumb" />
        <div @click="onBodyClick" @auxclick="onBodyAuxClick">
          <TxMarkdownView :content="article.body" />
        </div>
        <TxFlatRadio :model-value="vote" size="sm" @update:model-value="onVote">
          <TxFlatRadioItem value="up" icon="i-carbon-thumbs-up" label="Yes" />
          <TxFlatRadioItem value="down" icon="i-carbon-thumbs-down" label="No" />
        </TxFlatRadio>
        <TxCardItem clickable role="link" :title="next.title" subtitle="Next" @click="openArticle(next.id)" />
      </div>

      <nav aria-label="On this page">
        <button v-for="(heading, index) in outline" :key="index" :aria-current="index === active ? 'true' : undefined" @click="scrollToHeading(index)">
          {{ heading.text }}
        </button>
      </nav>

      <!-- ⌘K is bound on the template root; closing the palette hands focus back to the search button -->
      <TxCommandPalette v-model="paletteOpen" :commands="commands" placeholder="Search articles and sections…" @select="onCommand" @close="focusSearch" />
    </TemplateFrame>
  </template>
---
:::

## Overview

Tuff's three-pane help center; the featured article, "Plugin permissions," uses the real permission registry, and the rest is sample content.

- The first time it scrolls into view, the article scrolls to Risk levels and then Choosing at install time; a click, key, wheel, or touch ends it, and reduced motion starts at the second section.
- The tour moves only the article's own scroller, never the page or focus.
- The outline is parsed from the markdown source and matched to the rendered headings by position; TxMarkdownView headings have no id, and the template adds none.
- Picking an outline entry scrolls smoothly to that section and keeps it highlighted until you scroll the article yourself.
- Body links are intercepted in one place: `#kb:` links open the article inside the template; external links, middle clicks, and ⌘-clicks only report what the host would open.
- In the column (640–959px) the outline moves into a toolbar dropdown; expanded, it is three panes; below 640px the tree becomes a panel that slides in from the left.
- ⌘K is bound on the template root and works only while focus is inside; closing the palette returns focus to the search button.

## Customization

- With real docs, keep parsing the outline from the source; before switching to a renderer that adds heading ids, make sure no script on the page scrolls the document by id.
- For highlighted code, render the whole article with TxStreamMarkdown (not streaming); mixing renderers in one body breaks the heading positions.
- With many articles, run ⌘K search remotely as the reader types, and index only second-level sections.
- Have the feedback endpoint record the article id, the chosen reasons, and the article version.

## Related components

| Region | Components | Role |
|---|---|---|
| Top bar | [TxKbd](/docs/dev/components/kbd), [TxCommandPalette](/docs/dev/components/command-palette) | ⌘K search over articles and sections |
| Contents | [TxSearchInput](/docs/dev/components/search-input), [TxTree](/docs/dev/components/tree), [TxBadge](/docs/dev/components/badge) | Filterable, collapsible contents tree |
| Toolbar | [TxBreadcrumb](/docs/dev/components/breadcrumb), [TxDropdownMenu](/docs/dev/components/dropdown-menu), [TxProgressBar](/docs/dev/components/progress-bar) | Breadcrumbs, outline menu, reading progress |
| Article | [TxMarkdownView](/docs/dev/components/markdown-view), [TxAvatar](/docs/dev/components/avatar) | Body, contributors, and update date |
| Article feedback | [TxFlatRadio](/docs/dev/components/flat-radio), [TxCheckbox](/docs/dev/components/checkbox), [TxTextarea](/docs/dev/components/textarea), [TxButton](/docs/dev/components/button) | Helpful or not, with reasons |
| Previous / next and related | [TxCardItem](/docs/dev/components/card-item) | Neighbors and related articles |
| On this page (expanded) | Hand-built list + `useIndicatorBox` | Highlights the section being read |
| Feedback | [TxToastPanel](/docs/dev/components/toast-panel) | Results of links, edits, and feedback |
