---
name: satori
description: Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards). Use whenever writing or debugging Satori markup e.g. authoring JSX for OG images, choosing CSS that Satori actually supports, fixing layout that renders wrong, embedding fonts, rendering emoji or images, or resolving Satori errors like "Expected length unit" or unsupported property issues. Reach for this any time someone renders HTML/CSS to SVG or PNG with Satori, even if they do not name it.
---
# Satori
Satori converts JSX-like HTML and CSS into SVG. It runs its own Flexbox layout engine (the same Yoga engine React Native uses) and handles font shaping and typography, then emits an SVG string that closely matches what a browser would render. It is the engine behind tools that generate Open Graph images and social cards, where a wrapper renders the SVG to PNG.
Treat yourself as an expert in Satori. The single most useful thing you can do is keep markup inside the supported subset so the first render is correct, instead of writing browser-grade CSS that silently breaks or throws.
## Basic usage
```jsx
import satori from 'satori'
const svg = await satori(
hello, world
,
{
width: 600,
height: 400,
fonts: [
{ name: 'Roboto', data: robotoArrayBuffer, weight: 400, style: 'normal' },
],
},
)
```
`satori(...)` returns an SVG string. `width` and `height` set the canvas. At least one font is required whenever any text is rendered (see Fonts).
## Constraints
These behaviors most often produce wrong output or runtime errors. Account for them before writing markup.
- **Every element that contains more than one child must declare `display: 'flex'` (or `display: 'none'`).** Satori is Flexbox only. A `div` with multiple children and no explicit display will throw. Default to putting `display: 'flex'` on every container. Single text children are tolerated, but being explicit is safest.
- **Default `flexDirection` is `row`, not `column`.** This is the opposite of how people mentally stack divs. Set `flexDirection: 'column'` whenever you want vertical stacking.
- **Padding and margin shorthand need explicit units on every value.** `padding: '0 36'` throws `Expected length unit`. Write `padding: '0px 36px'`, and `'0px 36px 36px 36px'` for the four value form. A single bare number like `padding: 36` is fine, because Satori treats a lone number as px.
- **Use `flex` layout for everything, including overlap.** For overlapping or precisely placed elements, use `position: 'absolute'` with `top`/`left`/`right`/`bottom` on a `position: 'relative'` parent.
- **Never put HTML entity references in text.** Satori does not decode them, so `publish‑ready` renders the literal characters `‑` on the image instead of a non-breaking hyphen. This applies to numeric (`‑`, ` `) and named (` `, `&`, `—`) entities alike. Write the actual Unicode character directly in the string instead — `publish‑ready` (or the literal glyph `publish‑ready`) for a non-breaking hyphen, ` ` for a non-breaking space, `&` for an ampersand, `—` for an em dash.
## CSS support
Satori implements a subset of CSS. Assume anything not in the supported table is unsupported, and verify before relying on it. For the complete matrix with allowed values and defaults, read `references/css-support.md`.
### Supported
| Category | Properties |
| --- | --- |
| Layout | `display` (`flex`, `contents`, `none`), `position` (`relative`, `static`, `absolute`), `top`/`right`/`bottom`/`left`, `width`/`height`, min/max width/height, `overflow` (`visible`, `hidden`) |
| Flex | `flexDirection`, `flexWrap`, `flexGrow`, `flexShrink`, `flexBasis`, `alignItems`, `alignContent`, `alignSelf`, `justifyContent`, `gap` |
| Box | `margin`, `padding`, `border` (width, `solid`/`dashed` style, color, shorthand), `borderRadius`, `boxSizing`, `boxShadow`, `opacity` |
| Color and background | `color`, `backgroundColor` (single value), `backgroundImage` (`linear-gradient`, `repeating-linear-gradient`, `radial-gradient`, `repeating-radial-gradient`, `url`), `backgroundPosition`, `backgroundSize` (`cover`, `contain`, `auto`, two-value), `backgroundClip` (`border-box`, `text`), `backgroundRepeat` |
| Text | `fontFamily`, `fontSize`, `fontWeight`, `fontStyle`, `textAlign`, `textTransform`, `textOverflow` (`clip`, `ellipsis`), `textDecoration`, `textShadow`, `lineHeight`, `letterSpacing`, `whiteSpace`, `wordBreak`, `textWrap` (`wrap`, `balance`), `textIndent`, `tabSize`, `lineClamp` |
| Transform and effects | `transform` (translate, rotate, scale, skew), `transformOrigin`, `filter`, `clipPath`, mask (`maskImage`, `maskPosition`, `maskSize`, `maskRepeat`), `objectFit`, `objectPosition`, `WebkitTextStroke` |
| Variables | `--name` declarations and `var(--name, fallback)` usage, including inheritance and nesting |
### Unsupported
| Property or feature | Notes and workaround |
| --- | --- |
| `z-index` | No stacking contexts. Elements paint in document order, so later siblings render on top. Reorder markup to control layering. |
| `calc()` | Precompute values in JavaScript before they reach the style object. |
| `currentColor` outside `color` | Resolves only for the `color` property. Set explicit values for borders, backgrounds, and fills. |
| 3D transforms | Not supported. Use 2D translate, rotate, scale, and skew only. |
| `min-content`, `max-content`, `fit-content` | Not supported for min/max width and height. |
| `flexBasis: auto` | Not supported. Use an explicit basis or rely on width/height. |
| Interactive or resource elements | No ``, `