# Custom CSS and scripts

> For the complete documentation index, see [llms.txt](https://preview.writedocs.io/llms.txt).

Add your own styles and scripts - drop a .css or .js file in the project, or list scripts in writedocs.json.

## CSS and JavaScript files

Any `.css` or `.js` file in your project is loaded on every page. There's nothing to register:

```
my-docs/
├── writedocs.json
├── theme.css              ← loaded on every page
└── docs/
    ├── getting-started.mdx
    └── widgets.js         ← this too
```

Add, edit, rename or delete a file, and the site follows - `writedocs dev` picks up the change when you reload the page. Several files load in alphabetical order of their paths.

```css title="theme.css"
.wd-article h2 {
  letter-spacing: -0.01em;
}

/* Only in dark mode */
[data-theme="dark"] .featured-card {
  border-color: #2dd4bf;
}
```

The site's theme is on the `<html>` element: `data-theme="light"` or `data-theme="dark"`. To style one component, give it a class with `className` - see [Components](https://preview.writedocs.io/docs/content/components/#your-own-classes).

> Every `.css` and `.js` file in the project loads - including a draft you aren't using yet, or a script that belongs to something else. Files in a folder whose name starts with a dot (`.drafts/`), and in `node_modules/` and `dist/`, aren't loaded: keep the others there, or outside the project.

## `scripts`

For a script that isn't a file in your project - a widget from another service, say - or a few lines you'd rather keep in `writedocs.json`, list it in `scripts`:

```json
{
  "scripts": {
    "head": [
      { "src": "https://widget.example.com/loader.js" }
    ],
    "body": [
      { "content": "window.exampleWidget && window.exampleWidget.init({ id: 'docs' });" }
    ]
  }
}
```

**`head`** `array`

Scripts that load in the page's `<head>`, before the page is shown.

**`body`** `array`

Scripts that load at the end of the page, after its content. Most services' install instructions ask for this.

Each script has one of:

**`src`** `string`

A script's URL, or a path to a file in the project.

**`content`** `string`

The script's code.

A script with both, or neither, is an error in `writedocs validate`.

**`consent`** `boolean` default: `false`

`true` holds the script back until the reader accepts the [consent banner](https://preview.writedocs.io/docs/configuration/integrations/#consent-banner). Without the banner, the script loads like any other.

For analytics, check [Integrations](https://preview.writedocs.io/docs/configuration/integrations/) first: Google Analytics, Google Tag Manager, Plausible, Fathom, PostHog and Umami are turned on there with just an ID.