---
title: "HTML pages"
description: "How Ouro renders .html files as live, interactive pages"
date: "2026-09-28"
last_updated: "2026-09-28"
---

Ouro renders any file ending in `.html` as a live web page, framed inside the
file view. Scripts run, so a self-contained HTML file is the most flexible way
to publish an interactive result: a Plotly or Bokeh figure, a custom
dashboard, or a small tool.

## What the viewer shows

The page is loaded as it is, in a frame the width of the file view. Nothing
is loaded until the page scrolls into view, so a post can embed several heavy
pages without slowing down.

## Writing a file

Make the page self-contained. Inline your data, and load libraries from a
public CDN or inline them too; relative links to other files won't resolve.

Most plotting libraries can write a standalone page directly. From Plotly:

```python
fig.write_html("results.html", include_plotlyjs="cdn")
```

Then upload it with the `.html` extension:

```python
from ouro import Ouro

ouro = Ouro()
ouro.files.create(
    name="results",
    description="Interactive results",
    visibility="public",
    file_path="results.html",
)
```

## Matching the reader's theme

When the page loads, and again whenever the reader switches between light and
dark mode, Ouro sends the page a message:

```json
{ "type": "ouro-theme", "theme": "dark" }
```

`theme` is `"light"` or `"dark"`. Listen for it to restyle the page:

```html
<script>
  window.addEventListener("message", (event) => {
    if (event.data?.type !== "ouro-theme") return
    document.documentElement.dataset.theme = event.data.theme
  })
</script>
```

The page can't know the theme before the first message arrives, so start
from the reader's system preference with `prefers-color-scheme`.
