Satori: Enlightened library to convert HTML and CSS to SVG.
Note
To use Satori in your project to generate PNG images like Open Graph images and social cards, check out our announcement and Vercel’s Open Graph Image Generation →
To use it in Next.js, take a look at the Next.js Open Graph Image Generation template →
Satori supports the JSX syntax, which makes it very straightforward to use. Here’s an overview of the basic usage:
// api.jsx import satori from 'satori' const svg = await satori( <div style={{ color: 'black' }}>hello, world</div>, { width: 600, height: 400, fonts: [ { name: 'Roboto', // Use `fs` (Node.js only) or `fetch` to read the font as Buffer/ArrayBuffer and provide `data` here. data: robotoArrayBuffer, weight: 400, style: 'normal', }, ], }, )
Satori will render the element into a 600×400 SVG, and return the SVG string:
'<svg ...><path d="..." fill="black"></path></svg>'
Under the hood, it handles layout calculation, font, typography and more, to generate a SVG that matches the exact same HTML and CSS in a browser.
Satori only accepts JSX elements that are pure and stateless. You can use a subset of HTML elements (see section below), or custom React components, but React APIs such as useState
, useEffect
, dangerouslySetInnerHTML
are not supported.
If you don't have JSX transpiler enabled, you can simply pass React-elements-like objects that have type
, props.children
and props.style
(and other properties too) directly:
await satori( { type: 'div', props: { children: 'hello, world', style: { color: 'black' }, }, }, options )
Satori supports a limited subset of HTML and CSS features, due to its special use cases. In general, only these static and visible elements and properties that are implemented.
For example, the <input>
HTML element, the cursor
CSS property are not in consideration. And you can't use <style>
tags or external resources via <link>
or <script>
.
Also, Satori does not guarantee that the SVG will 100% match the browser-rendered HTML output since Satori implements its own layout engine based on the SVG 1.1 spec.
You can find the list of supported HTML elements and their preset styles here.
You can use <img>
to embed images. However, width
, and height
attributes are recommended to set:
await satori( <img src="https://picsum.photos/200/300" width={200} height={300} />, options )
When using background-image
, the image will be stretched to fit the element by default if you don't specify the size.
If you want to render the generated SVG to another image format such as PNG, it would be better to use base64 encoded image data (or buffer) directly as props.src
so no extra I/O is needed in Satori:
await satori( <img src="data:image/png;base64,..." width={200} height={300} />, // Or src={arrayBuffer}, src={buffer} options )
Satori uses the same Flexbox layout engine as React Native, and it’s not a complete CSS implementation. However, it supports a subset of the spec that covers most common CSS features:
Property Property Expanded Supported Values Exampledisplay
flex
, contents
, none
, default to flex
position
relative
, static
and absolute
, default to relative
color
Supported margin
marginTop
Supported marginRight
Supported marginBottom
Supported marginLeft
Supported Position top
Supported right
Supported bottom
Supported left
Supported Size width
Supported height
Supported Min & max size minWidth
Supported except for min-content
, max-content
and fit-content
minHeight
Supported except for min-content
, max-content
and fit-content
maxWidth
Supported except for min-content
, max-content
and fit-content
maxHeight
Supported except for min-content
, max-content
and fit-content
border
Width (borderWidth
, borderTopWidth
, ...) Supported Style (borderStyle
, borderTopStyle
, ...) solid
and dashed
, default to solid
Color (borderColor
, borderTopColor
, ...) Supported Shorthand (border
, borderTop
, ...) Supported, i.e. 1px solid gray
borderRadius
borderTopLeftRadius
Supported borderTopRightRadius
Supported borderBottomLeftRadius
Supported borderBottomRightRadius
Supported Shorthand Supported, i.e. 5px
, 50% / 5px
Flex flexDirection
column
, row
, row-reverse
, column-reverse
, default to row
flexWrap
wrap
, nowrap
, wrap-reverse
, default to wrap
flexGrow
Supported flexShrink
Supported flexBasis
Supported except for auto
alignItems
stretch
, center
, flex-start
, flex-end
, baseline
, normal
, default to stretch
alignContent
Supported alignSelf
Supported justifyContent
Supported gap
Supported Font fontFamily
Supported fontSize
Supported fontWeight
Supported fontStyle
Supported Text tabSize
Supported textAlign
start
, end
, left
, right
, center
, justify
, default to start
textTransform
none
, lowercase
, uppercase
, capitalize
, defaults to none
textOverflow
clip
, ellipsis
, defaults to clip
textDecoration
Support line types underline
and line-through
, and styles dotted
, dashed
, double
, solid
Example textShadow
Supported lineHeight
Supported letterSpacing
Supported whiteSpace
normal
, pre
, pre-wrap
, pre-line
, nowrap
, defaults to normal
wordBreak
normal
, break-all
, break-word
, keep-all
, defaults to normal
textWrap
wrap
, balance
, defaults to wrap
Background backgroundColor
Supported, single value backgroundImage
linear-gradient
, repeating-linear-gradient
, radial-gradient
, repeating-radial-gradient
, url
, single value backgroundPosition
Support single value backgroundSize
Support two-value size i.e. 10px 20%
backgroundClip
border-box
, text
backgroundRepeat
repeat
, repeat-x
, repeat-y
, no-repeat
, defaults to repeat
transform
Translate (translate
, translateX
, translateY
) Supported Rotate Supported Scale (scale
, scaleX
, scaleY
) Supported Skew (skew
, skewX
, skewY
) Supported transformOrigin
Support one-value and two-value syntax (both relative and absolute values) objectFit
contain
, cover
, none
, default to none
opacity
Supported boxSizing
Supported boxShadow
Supported overflow
visible
and hidden
, default to visible
filter
Supported clipPath
Supported Example lineClamp
Supported Example Mask maskImage
linear-gradient(...)
, radial-gradient(...)
, url(...)
Example maskPosition
Supported Example maskSize
Support two-value size i.e. 10px 20%
Example maskRepeat
repeat
, repeat-x
, repeat-y
, no-repeat
, defaults to repeat
Example WebkitTextStroke
WebkitTextStrokeWidth
Supported WebkitTextStrokeColor
Supported
Note:
z-index
support in SVG. Elements that come later in the document will be painted on top.calc
isn't supported.currentColor
support is only available for the color
property.Advanced typography features such as kerning, ligatures and other OpenType features are not currently supported.
RTL languages are not supported either.
Satori currently supports three font formats: TTF, OTF and WOFF. Note that WOFF2 is not supported at the moment. You must specify the font if any text is rendered with Satori, and pass the font data as ArrayBuffer (web) or Buffer (Node.js):
await satori( <div style={{ fontFamily: 'Inter' }}>Hello</div>, { width: 600, height: 400, fonts: [ { name: 'Inter', data: inter, weight: 400, style: 'normal', }, { name: 'Inter', data: interBold, weight: 700, style: 'normal', }, ], } )
Multiple fonts can be passed to Satori and used in fontFamily
.
Tip
We recommend you define global fonts instead of creating a new object and pass it to satori for better performance, if your fonts do not change. Read it for more detail
To render custom images for specific graphemes, you can use graphemeImages
option to map the grapheme to an image source:
await satori( <div>Next.js is 🤯!</div>, { ..., graphemeImages: { '🤯': 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/1f92f.svg', }, } )
The image will be resized to the current font-size (both width and height) as a square.
Satori supports rendering text in different locales. You can specify the supported locales via the lang
attribute:
await satori( <div lang="ja-JP">骨</div> )
Same characters can be rendered differently in different locales, you can specify the locale when necessary to force it to render with a specific font and locale. Check out this example to learn more.
Supported locales are exported as the Locale
enum type.
Satori supports dynamically loading emoji images (grapheme pictures) and fonts. The loadAdditionalAsset
function will be called when a text segment is rendered but missing the image or font:
await satori( <div>👋 你好</div>, { // `code` will be the detected language code, `emoji` if it's an Emoji, or `unknown` if not able to tell. // `segment` will be the content to render. loadAdditionalAsset: async (code: string, segment: string) => { if (code === 'emoji') { // if segment is an emoji return `data:image/svg+xml;base64,...` } // if segment is normal text return loadFontFromSystem(code) } } )
Satori can be used in browser, Node.js (>= 16), and Web Workers.
By default, Satori renders the text as <path>
in SVG, instead of <text>
. That means it embeds the font path data as inlined information, so succeeding processes (e.g. render the SVG on another platform) don’t need to deal with font files anymore.
You can turn off this behavior by setting embedFont
to false
, and Satori will use <text>
instead:
const svg = await satori( <div style={{ color: 'black' }}>hello, world</div>, { ..., embedFont: false, }, )
Set pointScaleFactor
to control how layout values are rounded to the pixel grid. This parameter is passed directly to Yoga’s pointScaleFactor
and improves rendering precision on high-DPI displays.
const svg = await satori( <div style={{ color: 'black' }}>hello, world</div>, { ..., pointScaleFactor: 2, }, )
To draw the bounding box for debugging, you can pass debug: true
as an option:
const svg = await satori( <div style={{ color: 'black' }}>hello, world</div>, { ..., debug: true, }, )
You can use the Vercel OG Image Playground to test and report bugs of Satori. Please follow our contribution guidelines before opening a Pull Request.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4