# Customization

## Configuration

Configure ReallySimpleDocs in `astro.config.mjs`:

```js title="astro.config.mjs"
import { defineConfig } from "astro/config";
import reallySimpleDocs from "reallysimpledocs/astro";

export default defineConfig({
  integrations: [
    reallySimpleDocs({
      docsDir: "./docs",
      routeBase: "/docs",
      customCss: ["./src/docs.css"],
      site: {
        title: "Acme Docs",
        subtitle: "v1.0.0",
        description: "Documentation for Acme.",
        url: "https://docs.example.com",
      },
    }),
  ],
});
```

| Option | Default | Notes |
|--------|---------|-------|
| `docsDir` | `"./docs"` | Folder containing Markdown or MDX pages and `docs.json`. |
| `routeBase` | `"/docs"` | URL path where the docs are mounted. Use `"/"` for root docs. |
| `style` | `"vega"` | Basecoat style: `vega`, `nova`, `maia`, `lyra`, `mira`, `luma`, `sera`, or `rhea`. |
| `customCss` | `[]` | CSS files imported after Basecoat and ReallySimpleDocs styles. |
| `css` | `true` | Set to `false` when you provide the full CSS pipeline yourself. |
| `bodyAttrs` | `{}` | Extra attributes added to `<body>`. |
| `components.Head` | Empty | Astro component appended to the document `<head>`. |
| `components.SidebarHeader` | Default header | Astro component used for the sidebar header. |
| `components.SidebarFooter` | Empty footer | Astro component used for the sidebar footer. |
| `components.ContentHeader` | Empty | Astro component rendered between search and the built-in theme toggle. |
| `site` | `{}` | Site metadata used by layout, SEO tags, and default UI. |
| `assetsBase` | `"/assets"` | Base path for relative favicon, social image, and logo asset values. |

## Site metadata

`site` controls the default sidebar header, document titles, and metadata:

```js title="astro.config.mjs"
reallySimpleDocs({
  site: {
    title: "Acme Docs",
    subtitle: "v1.0.0",
    description: "Documentation for Acme.",
    url: "https://docs.example.com",
    favicon: "favicon.svg",
    appleTouchIcon: "apple-touch-icon.png",
    socialImage: "social.png",
    logo: {
      url: "/assets/favicon.svg",
    },
  },
});
```

Relative asset values resolve from `assetsBase`, which defaults to `/assets`. Favicon and social image tags are emitted only when configured.

## Sitemap

Use Astro's sitemap integration when you need a sitemap. ReallySimpleDocs does not generate its own sitemap.

```bash
npm install @astrojs/sitemap
```

```js title="astro.config.mjs"
import sitemap from "@astrojs/sitemap";
import { defineConfig } from "astro/config";
import reallySimpleDocs from "reallysimpledocs/astro";

export default defineConfig({
  site: "https://docs.example.com",
  integrations: [reallySimpleDocs(), sitemap()],
});
```

The integration writes `sitemap-index.xml` and sitemap chunk files during `astro build`. It is not served by `astro dev`.

## Robots

Add `robots.txt` as a static file when you need one:

```txt title="public/robots.txt"
User-agent: *
Allow: /

Sitemap: https://docs.example.com/sitemap-index.xml
```

## Component overrides

Override layout regions when the default docs shell is not enough:

```js title="astro.config.mjs"
reallySimpleDocs({
  components: {
    Head: "./src/docs/Head.astro",
    SidebarHeader: "./src/components/SidebarHeader.astro",
    SidebarFooter: "./src/components/SidebarFooter.astro",
    ContentHeader: "./src/components/ContentHeader.astro",
  },
});
```

### Head

Use `Head` to add scripts, styles, preload tags, or site-specific metadata to the document `<head>`.
The default RSD head scripts and metadata still render.

```astro title="src/docs/Head.astro"
<script src="/assets/docs.js" defer></script>
```

`Head` receives `config`, `site`, `title`, `description`, `pagePath`, `metaTitle`, and `absoluteUrl`.

### SidebarHeader

Use `SidebarHeader` when the default logo/title block is not enough.

```astro title="src/components/SidebarHeader.astro"
---
const { site } = Astro.props;
---

<a href="/" class="btn" data-variant="ghost">
  {site.title}
</a>
```

### SidebarFooter

Use `SidebarFooter` for persistent sidebar actions or secondary links.

```astro title="src/components/SidebarFooter.astro"
<div class="p-2 text-xs text-muted-foreground">
  v1.0.0
</div>
```

### ContentHeader

Use `ContentHeader` for controls between search and the built-in theme toggle.
Header actions, such as a GitHub link, belong in this component rather than in `site` metadata.

```astro title="src/components/ContentHeader.astro"
<nav class="flex items-center gap-2">
  <a class="btn" data-variant="outline" data-size="sm" href="https://github.com/acme/project">
    GitHub
  </a>
</nav>
```

`ContentHeader` receives `site` and `page`.

Custom landing pages, marketing pages, blogs, and app pages should stay as normal Astro routes outside the ReallySimpleDocs docs route.

## CSS and Basecoat

ReallySimpleDocs is built on [Basecoat](https://basecoatui.com). Pick a Basecoat style with `style`, then add project-specific CSS with `customCss`:

```js title="astro.config.mjs"
reallySimpleDocs({
  style: "nova",
  customCss: ["./src/docs.css"],
});
```

```css title="src/docs.css"
:root {
  --primary: oklch(54.6% 0.245 262.881);
}

.dark {
  --primary: oklch(70.7% 0.165 254.624);
}
```

By default, ReallySimpleDocs manages one Tailwind/Basecoat stylesheet for the app. It scans:

- `src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}`
- `docs/**/*.{md,mdx}`
- ReallySimpleDocs runtime components

That means custom Astro pages outside the docs route can use Tailwind and Basecoat classes without a separate stylesheet.

## Managed CSS

Disable managed CSS only when you want to own the full stylesheet pipeline:

```js title="astro.config.mjs"
reallySimpleDocs({
  css: false,
});
```

With managed CSS enabled, ReallySimpleDocs inserts:

- Tailwind
- the selected Basecoat style
- RSD layout/component CSS
- each `customCss` file

Use `css: false` when you bring your own Tailwind/Basecoat/RSD stylesheet.

When managed CSS is disabled, import RSD's own docs CSS from the public package entry:

```css title="src/docs.css"
@import "reallysimpledocs/css";
@import "reallysimpledocs/css/styles/vega";
```

Use the `reallysimpledocs/css/styles/{style}` import that matches your Basecoat style.

ReallySimpleDocs always inserts its managed JavaScript: theme initialization, Basecoat JavaScript, copy-code behavior, and command search behavior.

When you disable managed CSS, use these source files as references for what you may need to reproduce:

- [DefaultHead.astro](https://github.com/hunvreus/reallysimpledocs/blob/main/src/runtime/components/DefaultHead.astro): theme initialization, Basecoat JavaScript, and copy-code behavior.
- [ThemeToggle.astro](https://github.com/hunvreus/reallysimpledocs/blob/main/src/runtime/components/ThemeToggle.astro): built-in dark-mode button.
- [CommandDialog.astro](https://github.com/hunvreus/reallysimpledocs/blob/main/src/runtime/components/CommandDialog.astro): search dialog behavior.
- [Sidebar.astro](https://github.com/hunvreus/reallysimpledocs/blob/main/src/runtime/components/Sidebar.astro): sidebar shell and toggle target.
- [reallysimpledocs/css](https://github.com/hunvreus/reallysimpledocs/blob/main/src/css/custom.css): shared RSD-specific CSS layered on top of Basecoat.
- [reallysimpledocs/css/styles/*](https://github.com/hunvreus/reallysimpledocs/tree/main/src/css/styles): style-specific RSD CSS for code and tabbed surfaces.

Prefer `style` and `customCss` for normal styling changes, and `Head` or `ContentHeader` for additive UI. Use `css: false` only when you are replacing RSD's stylesheet pipeline.

## Public files

Put docs media in `public/media/` and reference it with absolute paths:

```md title="docs/page.md"
![Diagram](/media/diagram.png)
```

Put favicon and social assets in `public/assets/` when using the default `assetsBase`.

## Search

Search uses a generated Lunr index. ReallySimpleDocs indexes normalized Markdown, including fallback Markdown for known MDX components, while keeping code examples separate so prose matches stay readable.

Render the exported `CommandDialog` on any Astro page when you want docs search outside the ReallySimpleDocs route:

```astro title="src/pages/index.astro"
---
import { CommandDialog } from "reallysimpledocs/components";
---

<CommandDialog />

<button type="button" class="btn" onclick="window.rsdOpenCommandSearch?.()">
  Search docs
</button>
```

`CommandDialog` uses the generated docs search index by default. Pass `indexUrl` only when you need to point at a different index.

```astro title="src/pages/index.astro"
<CommandDialog indexUrl="/docs/search-index.json" />
```

The dialog registers `window.rsdOpenCommandSearch()` and the `⌘K` / `Ctrl+K` shortcut on pages where it is rendered.

## htmx

Install htmx first:

```bash
npm install htmx.org
```

Use `bodyAttrs` to boost links into the docs content container.
Because the sidebar is outside `#content`, update its current-page state from `Head` after htmx swaps:

<CodeGroup>
```js title="astro.config.mjs"
reallySimpleDocs({
  bodyAttrs: {
    "hx-boost": "true",
    "hx-target": "#content",
    "hx-select": "#content",
    "hx-swap": "outerHTML",
    "hx-push-url": "true",
  },
  components: {
    Head: "./src/docs/Head.astro",
  },
});
```

```astro title="src/docs/Head.astro"
---
import htmxUrl from "htmx.org/dist/htmx.min.js?url";
---

<script is:inline>
  (() => {
    const key = (href) => {
      const url = new URL(href, window.location.origin);
      return `${url.pathname.replace(/\/$/, "")}${url.search}`;
    };

    const syncSidebar = () => {
      for (const link of document.querySelectorAll("#sidebar a[href]")) {
        const isCurrent = key(link.href) === key(window.location.href);
        if (isCurrent) {
          link.setAttribute("aria-current", "page");
          link.closest("details")?.setAttribute("open", "");
        } else {
          link.removeAttribute("aria-current");
        }
      }
    };

    document.addEventListener("DOMContentLoaded", syncSidebar);
    document.addEventListener("htmx:afterSettle", () => {
      window.basecoat?.initAll?.();
      syncSidebar();
    });
    window.addEventListener("popstate", syncSidebar);
  })();
</script>

<script src={htmxUrl} defer></script>
```

</CodeGroup>

Using a CDN is also fine; see the [htmx installation docs](https://htmx.org/docs/#installing) for options.
