# SVG assets

> Drop a `.svg` into `model/art/` and render it with `Svg(Art.Hexgrid)`. Unlike an icon, an asset keeps its own colours, gradients and patterns — it is the illustration, background or multi-colour logo counterpart to the single-colour `Icon`. The name is checked at compile time, and the asset is placed with ordinary style props.

<!-- id: ui-svg-assets · area: ui · stability: stable · html: https://osysharp.com/reference/ui/svg-assets/ -->

## Summary        {#summary}
An SVG asset is a **file in your app**, not data. Put a `.svg` in `model/art/` and it becomes part of your app's
vocabulary:

```text
model/
  art/
    hexgrid.svg
    hero.svg
    logo-full.svg
```

```osy title="an asset behind a page" test app=arcade
[Composable]
component Splash() {
  render {
    Box(position: Position.Relative, minH: "100vh") {
      Svg(Art.Hexgrid, position: Position.Absolute, inset: 0, z: "-1");   // a full-bleed background
      Text("Welcome");
    }
  }
}
```

This compiles against the [drop-ship-order](#see-also) sample, whose `art/` folder really does contain `hexgrid.svg`
— the name is checked against the files the app ships.

Adding an asset is dropping a file in. There is nothing to register and nothing to import.

## Signature      {#signature}
```osy syntax
Svg(Art.Hexgrid) · Svg(Art.Hexgrid, position: Position.Absolute, inset: 0) — a named SVG asset, placed with style props
```

## Description    {#description}

### Asset or icon?   {#vs-icon}
Reach for an **asset** when the artwork carries its own colours — an illustration, a background pattern, a hero
image, a full-colour logo. Reach for an [icon](https://osysharp.com/reference/ui/icons/) when it's a single-colour glyph that should follow the
surrounding text colour.

| | `Icon(name)` | `Svg(name)` |
|---|---|---|
| Lives in | `model/icons/` | `model/art/` |
| Colour | recoloured to the current text colour | **its own** colours, gradients, `<pattern>`s |
| Sizing | an em square (`size:`) | placed with style props (`w:`/`h:`/`position:`/…) |
| For | UI glyphs | illustrations, backgrounds, multi-colour logos |

### The name is checked   {#names}
`Svg(Art.Hexgrid)` names the asset by a **bare identifier**, checked against the assets your app actually declares. A
typo is a compile error with a suggestion:

```text
unknown SVG asset 'hexgrd' (declared assets: hero, hexgrid, logo). Did you mean 'hexgrid'?
```

Because the name is an identifier, an asset's **file name must be one too** — `logo_full.svg`, not
`logo-full.svg`. A kebab-case file is rejected with the rename to make.

The name is never an expression. A local variable called `hexgrid` does **not** change what `Svg(Art.Hexgrid)` means —
the asset vocabulary always wins. An asset chosen at runtime is a *content* concern, not chrome: use `Image(src)`
for that.

### Sizing and placing an asset — ordinary style props   {#placement}
An asset keeps its own colours, so there is no `size:`/`color:`. Instead it takes the ordinary
[style props](https://osysharp.com/reference/ui/styling/), so you place it like any other element — a sized inline logo, or a full-bleed
background behind a card:

```osy title="placing one with ordinary style props" test app=arcade
[Composable]
component Wordmark() {
  render { Svg(Art.LogoFull, w: 140); }            // an inline, fixed-width logo
}

[Composable]
component Patterned() {
  render {
    Box(position: Position.Relative) {
      Svg(Art.Hexgrid, position: Position.Absolute, inset: 0, z: "-1");   // tiles behind the box's content
      Slot;
    }
  }
}
```

By default an asset fills the box you give it, so a full-bleed background is `position: Position.Absolute; inset: 0` on a
`position: Position.Relative` parent, and a fixed-size asset is just `w:`/`h:`. Anything other than the asset name and style
props is a compile error.

### What an asset may contain   {#contents}
An asset is drawing: shapes, groups, and the paint machinery that gives it colour — `linearGradient`,
`radialGradient`, `pattern`, `clipPath`, `mask`, and a `<defs>` block, with in-document `fill="url(#…)"` references
to them. Its colours are kept exactly as drawn.

Anything that could **run, load, or reach outside the file** is a compile error, naming the file:

```text
'evil.svg' contains a <script> element — scripting, styling, embedding, external
references and animation are not allowed in an SVG asset.
```

That covers `<script>`, `<style>`, `<image>`, `<use>`, `<a>`, animation elements, any `on…` handler, and any URL
that leaves the document — an external or `data:` image, a `javascript:` link, a `url(https://…)`. A `url(#id)`
that points **inside the same asset** (a gradient or pattern fill) is fine; each asset's ids are kept separate, so
two assets that happen to use the same id never collide. An SVG is a place scripts can hide, and your assets are
placed directly into your pages — so the rule is an allow-list, and it is not negotiable.

### Assets from a UI kit   {#kits}
A kit's assets land in your app tree alongside your own and are picked up the same way. Two files claiming the same
name is an error naming both, so an asset always resolves to exactly one file.

### How assets are delivered — inline, on the first byte   {#delivery}
A server-rendered page paints its assets inline on the very first byte — no request, no flash. Change an asset and
the delivered copy changes with it; leave it alone and browsers keep the copy they already have.

Custom glob, if `model/art/` doesn't suit you:

```osy syntax
app Admin {
  model "model/**/*.osy";
  svg "assets/art/*.svg";
}
```

### Passing an asset around — `Art` is a type   {#as-a-value}
`Art` is a type, so an SVG asset can be a component parameter, a return value or a stored field:

```osy syntax
[Composable]
component Badge(string label, Art art) {
  render {
    Stack {
      Svg(art, w: 120);
      Text(label);
    }
  }
}

// at the call site
Badge("Grid", Art.Hexgrid);
```

The vocabulary is built from the files themselves, so there is nothing to declare — and an app that ships no
`model/art/` files simply has no `Art` type yet, which the compiler says in those words.

## See also   {#see-also}
- [icons](https://osysharp.com/reference/ui/icons/) — the single-colour glyph counterpart, recoloured to the current text colour.
- [style props](https://osysharp.com/reference/ui/styling/) — the `position`/`inset`/`w`/`h` props that place an asset.
- [theme tokens](https://osysharp.com/reference/ui/theming/) — the tokens the surrounding layout resolves against.
