Skip to main content
Compose your custom layouts with Lettercamp’s optional UI components. Each provides working UI, default styling, and its existing behavior. Place them where you want, omit them, or render your own UI from the layout data. Lettercamp does not automatically insert missing controls into a custom layout.
This import works in local previews, standalone builds, and Lettercamp Cloud. The CLI provides it; you do not install another package. Use the helpers inside custom React layouts, cards, headers, or footers. Layout overrides hydrate automatically, so you do not add client:load to their nested components. All public elements accept className and style on their root element. SearchButton and ShareButton also accept normal button attributes and children for a custom label or icon. Keep an accessible label for icon-only buttons.
These are the same elements used by the default site. Header includes branding, navigation, the primary link, and the mobile menu. Footer includes branding, link columns, social links, and the Lettercamp credit. Pass site to use the current header, footer, and branding settings. Header uses pathname to mark the current navigation link. Both accept className and style on their root. Publication-relative links from settings are resolved automatically. Importing these elements always renders the default; it never calls your components/layouts/Header.jsx or Footer.jsx override. That lets an override safely wrap the default element.

PostCard

Renders the standard cover, date, category, title, description, and authors. Pass a normalized post from your layout. priority defaults to false; set it for the first listing card to load its image eagerly. className and style apply to the article root. This import always renders the standard card. In contrast, the PostCard prop provided to PostList and PostLayout selects your card override when one exists, and otherwise uses this default. RelatedPosts makes the same selection.

PostHeader

Renders the same article header as the default site: category, title, description, author/date/reading-time byline, sharing controls, and cover image. It does not include the article body, TOC, or related posts; your layout arranges those. Reading-time visibility follows site.post.showReadingTime. The header uses site.post.contentWidthEm and the post’s cover sizing metadata. To replace the byline or title structure, compose your own header with PostByline and ShareButton instead.

PostByline

Displays publication date, author names and avatars, the additional-authors popup, and reading time. Pass the normalized post supplied to your custom layout or card. For cards, use showReadingTime={false} to match the default card behavior. You can also display post.authors, post.date.label, or post.readingMinutes with your own markup.

SearchButton

Opens the shared search dialog with matching, highlighted results, loading and empty states, arrow-key navigation, Escape dismissal, and focus restoration. Several buttons on a page share one dialog. The default label is “Search articles…” with a search icon; narrow screens show the icon. Custom children replace that content. Set aria-label when you need a different accessible label. You can place a button in an article layout or header as well as a post list. Search covers published article titles, descriptions, and extracted body text. It uses the generated search-index.json beneath your publication’s base URL. The index updates when you build or publish. Online draft previews still search that last built index; unsaved drafts are not added to search results. Search results keep their own UI rather than using your custom PostCard. For completely different search behavior, build your own UI. The index is a JSON array with title, href, summary, text, category, and formatted date; image and imageAttributes may also be present. Use supplied URLs directly. The default search does not require a custom search service or a hook API.

ShareButton

Opens the existing share dialog, including copy link, sharing destinations, and summarization links. The default label is “Share” with an icon. The dialog reads the current page’s canonical URL and metadata when opened, including updated metadata in a draft preview. It shares the current page; putting it in a listing card does not make it share that card’s destination.

TableOfContents

Defaults to the floating control on the left edge, matching the vertical article layout. Hover, focus, or tap the indicators to open the section links. It tracks the active heading; Escape closes it. Without JavaScript, the heading links render in the document flow. No dropdown wrapper or positioning CSS is needed. The starter explicitly selects sidebar for a horizontal (split) article. The sidebar is hidden at narrow widths in the standard article layout; the floating variant remains available. Heading targets stay inside Lettercamp’s managed article body, so keep rendering children.

Pagination

Renders previous/next links, page numbers, ellipses, disabled end controls, and the current-page state. It renders nothing when there is only one page. Pass current, total, and base, all included in PostList’s pagination prop. base is the supplied listing URL, including its category and any publication subfolder. Do not prepend the subfolder again. Pagination follows normal links; Lettercamp handles those links inside the online preview too.

CategoryNavigation

Renders “All” and the supplied category links, marking the selected category. categories contains { name, href } objects; category is the selected name or "" for all posts. Both come from PostList. Set allLabel to change “All.” Use CSS to arrange the links as tabs, pills, or a wrapping list.
Renders the supplied related posts using your PostCard override, or Lettercamp’s default card when you have no override. Lettercamp calculates the related posts; the component presents them. The default grid uses three columns, two at tablet widths, and one on small screens. Override the grid with CSS, or map relatedPosts yourself for a different structure.

Style the components

Use CSS Modules for your layout and the documented global classes for component parts. For example, pass className={styles.byline} and style it locally:
Import a global stylesheet once from your layout for dialogs, which render outside your layout wrapper:
These classes are supported styling hooks: Use ::backdrop to style the search and share dialog backdrops. Shared colors and fonts use the site’s CSS variables, including --site-background, --site-foreground, --site-border, and --font-family. Keep visible focus states and readable contrast, and avoid changing interaction attributes or hiding controls the reader needs. CSS changes appearance; it does not replace search ranking, popup behavior, or sharing actions.

Preview and editing

The starter’s examples/layouts/ files use these elements and standard styles. Copy them to components/layouts/ to customize the arrangement. They run inside the online custom-layout preview using the last built components and current draft data. Pass the layout’s site prop to settings-aware helpers; omitting it uses the built settings instead of live settings changes. Article text, tables, images, and other rich blocks remain managed through children. These UI helpers do not change the editor’s content format. Custom headers and footers still use the existing online placeholders. Helpers placed inside an MDX article follow the usual custom-MDX placeholder behavior. Publish component or stylesheet changes to update their online preview bundle. Use lettercamp dev while developing locally.