Skip to main content

examples/html_linked_scoped_css.livemd

# HTML Linked With Scoped CSS

```elixir
Mix.install([
  {:lumis, path: ".."}
])
```

`formatter: :html_linked` renders classes instead of inline styles. This is useful when your app has a strict Content Security Policy or when many code blocks share the same stylesheet.

```elixir
code = """
defmodule Demo do
  def hello(name), do: "hello #{name}"
end
"""

html =
  Lumis.highlight!(code,
    formatter: {:html_linked, language: "elixir"}
  )
```

The generated HTML contains semantic token classes:

```elixir
html
```

Build CSS for the light theme:

```elixir
light_css = Lumis.Theme.build_css!("github_light")
```

By default, Lumis emits the same selector shape as the bundled CSS files:

```css
.lumis {
  color: #1f2328;
  background-color: #ffffff;
}
.l-keyword {
  color: #cf222e;
}
```

Use `:container_selector` when your code block uses a different wrapper class. This changes only the container rule selector:

```elixir
Lumis.Theme.build_css!("github_light",
  container_selector: ".code-block"
)
```

Output shape:

```css
.code-block {
  color: #1f2328;
  background-color: #ffffff;
}
.l-keyword {
  color: #cf222e;
}
```

Use `:scope` to put every selector under a parent selector. This is commonly used for manual dark mode selectors:

```elixir
dark_css =
  Lumis.Theme.build_css!("github_dark",
    scope: ~s(html[data-theme="dark"]),
    container_selector: ".lumis",
    container_style: [
      {"background-color", "var(--code-background)"},
      {"border-radius", "0.375rem"},
      {"padding", "1rem"},
      {"overflow-x", "auto"}
    ]
  )
```

Output shape:

```css
html[data-theme="dark"] .lumis {
  color: #e6edf3;
  background-color: var(--code-background);
  border-radius: 0.375rem;
  padding: 1rem;
  overflow-x: auto;
}
html[data-theme="dark"] .l-keyword {
  color: #ff7b72;
}
```

You can combine light and dark CSS and embed or serve the result however your application needs:

```elixir
css = light_css <> "\n\n" <> dark_css
```