# Post Page

> A whole blog post page, built from our website components: a floating navbar, the post with its author and a list of its sections, other posts to read next, a closing band, and a footer.

- Name: `post-page`
- Status: beta
- Categories: blog, post, article, marketing, page
- Files: the install writes `post-page.tsx`, and any part files named `post-page-*.tsx`, to your `components` alias, `@/components` by default. Edit them freely. They are yours.
- Other registry items: `@arbokui/navbar`, `@arbokui/article`, `@arbokui/headline`, `@arbokui/post-grid`, `@arbokui/call-to-action-band`, `@arbokui/footer`. The install adds them.
- Gallery: https://arbokui.com/templates/post-page
- Registry item: https://arbokui.com/r/post-page.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the template. It also adds every component it uses:

   ```bash
   npx shadcn@latest add @arbokui/post-page
   ```

## Use it for

- One post on a product site's blog. Render it as the whole page, from your app's page file, once per post.
- Pass the post in \`article\`: its title, date, author, and the post itself as \`article.children\`, in plain HTML like p, h2, ul, and pre.
- Give the post two or more h2s. On wide screens a list of them sits beside the post.
- Set \`article.back\` to link to the list of posts, which Blog Page draws.
- Use \`more\` for up to three other posts, like the newest ones. Leave out the post on this page.
- Pass your router's link once in \`renderLink\`. From a server page, render the page from a client file, since a server page cannot pass a function. Pass the post's body from the server page as children, so it is not sent as code.
- Set \`embedded\` when you show the page inside another page, like a gallery, so it has no second main.

## Avoid it for

- A second h1. The post's title is the page's h1.
- More than three other posts. Link to the blog for the rest.

## Props

- `navbar`: `NavbarProps`. The Navbar's props. It floats as a pill once the page scrolls, and folds into a menu below 42rem.
- `article`: `ArticleProps`. Required. Article's props: \`title\`, \`date\`, \`author\`, \`back\`, \`cover\`, and the post as \`children\`. The title renders as the page's one h1.
- `more`: `{ id?: string; headline?: HeadlineProps; posts: Post[] }`. Other posts to read next, as Post Grid cards, under a headline that defaults to "More posts.". Its id defaults to "more".
- `cta`: `CallToActionBandProps`. The closing band above the footer.
- `footer`: `FooterProps`. The Footer's props.
- `renderLink`: `(props: NavbarLinkProps) => ReactNode`. Default `a plain <a>`. Draws every link in the navbar, the back link, the other posts, the closing band, and the footer, unless a part sets its own.
- `embedded`: `boolean`. Default `false`. Renders the content in a div, not a main, for a preview inside another page.
- `className`: `string`. Extra classes on the root, which holds the container query.

## Accessibility

- The content sits in a main landmark, between the navbar's nav and the footer, so skip links and screen readers find it.
- The post's title is the page's one h1. The post's sections and the More posts headline are h2s, and each other post's title an h3.
- Each part keeps its own accessibility, listed on its page.

## Examples

### A short post page

```tsx
<PostPage
  navbar={{ brand: "Workspace", links: [{ href: "/blog", label: "Blog", current: true }] }}
  article={{
    back: { href: "/blog", label: "All posts" },
    title: "How to plan a release",
    date: "2026-10-12",
    tag: "Guides",
    // The same cover as the post's card on the blog.
    cover: <PostGridCover post={{ href: "/blog/plan-a-release", tag: "Guides" }} />,
    children: (
      <>
        <p>A release goes better when everyone knows what is in it.</p>
        <h2>Write down the scope</h2>
        <p>Start with a short list of what the release changes.</p>
      </>
    ),
  }}
  more={{ posts: [{ href: "/blog/shared-folders", title: "Shared folders are here", date: "2026-10-28" }] }}
  footer={{
    brand: "Workspace",
    columns: [{ title: "Company", links: [{ href: "/blog", label: "Blog" }] }],
    legal: "© 2026 Workspace",
  }}
/>
```
