Migrate from Emotion
@elastic/distillate/emotion is an @emotion/css-shaped surface over a distillery: css, cx, injectGlobal, stylesheet, globalModules. Nested & and @media use stylis, so existing templates keep their meaning.
import { createEmotion, createDomSink } from '@elastic/distillate/emotion';
const sink = createDomSink({ document });
const { css, cx, injectGlobal } = createEmotion(distillery, { sink });
| Emotion | Distillate |
|---|---|
css\...`` |
css\...`` — returns a handle that stringifies to the readable class. |
cx(...) |
cx(...) — strings, numbers, falsy, arrays, maps, handles. |
injectGlobal |
injectGlobal — registered as a module; ships in stylesheet(). |
<style> injection |
createDomSink — one element, rewritten on each registration, one flush per turn. |
| Emotion | Status |
|---|---|
css({ color: 'red' }) |
Rejected. Tagged templates only. |
keyframes |
Rejected. |
@supports / @container in css |
Rejected. Use container(...) from the root entry. |
styled.* / @emotion/react css prop |
Out of scope. |
| Runtime template values | Styles are static after first construction. Put variation on CSS variables. |
String(css\...`)is the readable class name and **does not collect**. Use it only against a readable stylesheet (the DOM sink orstylesheet()`).
The same value passed through resolveClassName / collector.useHandles participates in compact artifact emission. SSR: render stylesheet() on the server; content hashes make client and server class names agree.
Do not rely on declaration order across separate css calls. Interpolate:
const base = css`
color: red;
`;
const ext = css`
${base}
color: blue;
`;
- Compose by interpolation. Both declarations land on
ext's class; later wins.
cx accepts native StyleHandle values and uses their readableName. A host can migrate file by file: new modules through createStyleModule, remaining call sites through createEmotion on the same distillery.