> ## Documentation Index
> Fetch the complete documentation index at: https://www.lettercamp.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# React components

> Import your own React components into MDX articles and add interactive examples.

For built-in article blocks such as images, code, and tables, use [content components](https://www.lettercamp.com/docs/components/overview.md) without imports. Use custom React components for your own UI and interactions.

Add React components to your publication repository and import them into `.mdx`
pages. Lettercamp includes React and its renderer with the CLI.

## Supported imports

For Lettercamp Cloud, custom components can import `react`, `react-dom`, `lettercamp/components`, and local
components, JavaScript or TypeScript helpers, and CSS or Sass files. Keep supporting
source files in `components/`, `lib/`, `styles/`, or `assets/`.

* Import [reusable UI components](https://www.lettercamp.com/docs/ui-components.md) from `lettercamp/components`.
  This CLI-provided entry point needs no separate installation.
* Use relative imports such as `./Footer.module.css` or `../lib/links.ts`.
  Match filename casing exactly; Cloud's file system is case-sensitive.
* Do not use `#blog/...` aliases from `package.json`, `@/...` aliases from
  `tsconfig.json`, or aliases configured in another project's bundler.
  These configurations are not included in CLI deployments.
* Use `.css`, `.scss`, or `.sass`, including `.module.css` and `.module.scss`.
  Lettercamp includes the Sass compiler. Less and Stylus are not provided.
* Do not import other npm packages, including `react-icons`, `lucide-react`,
  UI kits, or Next.js components. Use inline `<svg>` elements or small local icon
  components, and standard `<a>` and `<img>` elements for links and images.

Installing a package locally or adding it to `package.json` does not make it
available when publishing to Lettercamp. A local preview or build can succeed by
using packages installed on your computer that are unavailable in hosted builds.
Do not rely on packages used internally by Lettercamp either.

For images or fonts needed by a custom component, an agent can
[upload assets with the signed-in CLI](https://www.lettercamp.com/docs/cli/upload.md#let-an-agent-upload-assets)
and use the returned hosted URLs in the component or its CSS.

After each component change, run [`npx lettercamp check`](https://www.lettercamp.com/docs/cli/check). Agents can
use `npx lettercamp check --json`, fix the reported files, and repeat until the
full check passes. Do not install a missing library or externalize it in a bundler
configuration to work around a Cloud compatibility error.

If you [build for another host](https://www.lettercamp.com/docs/publishing/build.md), your components can use
dependencies installed in your own build environment.

## Try the starter calculator

The [bundled starter](https://github.com/lettercamp/lettercamp/tree/main/core/starter) includes
`components/ReadingTimeCalculator.jsx`. Readers can enter a word count or choose a
preset to estimate reading time at 200 words per minute, rounded up to whole
minutes. Zero words produces zero minutes.

To use it in a page,
add the import after the frontmatter, then place the component where you want it:

```mdx theme={null}
---
title: "Plan your next article"
description: "Estimate how long your article will take to read."
---

import ReadingTimeCalculator from '../components/ReadingTimeCalculator.jsx';

## Estimate reading time

<ReadingTimeCalculator client:visible initialWords={600} />
```

The `initialWords` prop sets the starting word count and defaults to `600`.
The calculator uses the count the reader enters.

## Create your own component

For an existing cloud site, [connect your local coding agent](https://www.lettercamp.com/docs/cli/connect.md) to
download its source. Develop locally, then use `lettercamp push` to review a cloud
preview before publishing from the website.

Keep reusable components in `components/` or an optional `components/elements/`
subfolder beside `pages/`. Reserve `components/layouts/` for the five
automatically detected [layout overrides](https://www.lettercamp.com/docs/custom-layout.md#override-files-and-fallback). Use `.jsx` for
JavaScript or `.tsx` for TypeScript. Import local files using paths relative to the
MDX page, including the file extension.

```text theme={null}
my-publication/
├── components/
│   └── Counter.jsx
├── pages/
│   └── example.mdx
└── settings.json
```

For example, create `components/Counter.jsx`:

```jsx theme={null}
import { useState } from 'react';

export default function Counter({ initialCount = 0 }) {
  const [count, setCount] = useState(initialCount);

  return (
    <button type="button" onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}
```

Import it in a page under `pages/`:

```mdx theme={null}
import Counter from '../components/Counter.jsx';

<Counter client:visible initialCount={0} />
```

Import components directly in the `.mdx` page that uses them.
Components can import other local components and use
React hooks such as `useState` and `useEffect`.

## Style your component

Import a CSS Module from your component, for example
`import styles from './Counter.module.css'`, then use a local class with
`className={styles.counter}`. Lettercamp bundles the CSS and generates unique
class names. Commit both files. Plain `.css` imports are global and can affect
other parts of your publication; inherited fonts and global element styles still
apply with CSS Modules.

You can also replace your publication's [header or footer](https://www.lettercamp.com/docs/custom-layout.md) with a
React component using the same styling approach.

## Choose when a component becomes interactive

Lettercamp renders React components to HTML during the build. Add a client
directive when a component needs event handlers or state updates in the browser.

Place the client directive on the component's usage in MDX to choose when it
becomes interactive:

| Usage | Behavior |
| - | - |
| `<Component />` | Renders HTML with no browser JavaScript for this component. |
| `<Component client:visible />` | Becomes interactive when it enters the viewport. A good default for article widgets. |
| `<Component client:load />` | Loads its JavaScript immediately for interactions needed as soon as the page opens. |

Use strings, numbers, booleans, arrays, and plain objects for props passed to
interactive components. Define event handlers inside the component instead of
passing functions from MDX.

Components with `client:visible` or `client:load` also render during the build.
Access browser APIs such as `window` and `localStorage` in an effect or event
handler, rather than at module scope or during the initial render.

## Edit in the web editor

Both **Edit** and the page's **Preview** show custom React components as labeled
placeholders. Each placeholder marks the component's position on the page.
Inline components appear as small labels within the text.

Imports and exports stay in **Source** and are preserved when you edit the page.
Use a placeholder's **Edit source** button to change its MDX props or imports.
To change the component implementation, edit its `.jsx` or `.tsx` file in your
publication repository.

Use **Preview** for a read-only content preview of the current page, including
unsaved text and component placeholders. Use `npx lettercamp dev` to check the
publication's full layout and interactive React components.

## Preview locally

Run `npx lettercamp dev` from your publication folder. Imported component changes
update the local preview automatically. This is useful when developing a component
and checking repeated changes to its code.

```sh theme={null}
npx lettercamp dev
```

Open the URL printed in the terminal. Set `draft: false` in your example page's
frontmatter to include it in the local site. Use the web editor's **Preview** to
view draft content and component placeholders.

## Publish

For a workspace downloaded with `lettercamp connect`, run `lettercamp check`,
then `lettercamp push`. Review the result in **Settings → Agent connections** and
choose **Publish this preview**. See [Connect and sync](https://www.lettercamp.com/docs/cli/connect.md).

For Lettercamp Cloud, run [`npx lettercamp check`](https://www.lettercamp.com/docs/cli/check), then
[`npx lettercamp deploy`](https://www.lettercamp.com/docs/publishing/deploy).

For another host, run `npx lettercamp build --site https://example.com` to generate the HTML and
JavaScript for hosting. Upload the entire output directory, including its generated
assets, so interactive components can load.

Commit component files alongside the MDX pages that import them. Hosted builds
read those files from your publication repository. Check your components against
the [supported imports](#supported-imports) before publishing.

## Troubleshooting

* **The component appears but does not respond:** add `client:visible` or
  `client:load` to its usage in MDX. With `client:visible`, scroll the component
  into view before trying it. For a self-hosted site, also check that its generated
  JavaScript assets were uploaded.
* **The import cannot be resolved:** check the relative path, filename casing,
  file extension, and matching default or named export. Commit the component file
  to the repository used by hosted builds.
* **The build reports that `window` or `document` is undefined:** move browser-only
  code into `useEffect` or an event handler. Interactive components also render
  outside the browser during the build.

Run [`npx lettercamp check`](https://www.lettercamp.com/docs/cli/check) to check Cloud compatibility before
publishing, and `npx lettercamp dev` to verify appearance and interactions.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.