SolidJS's fine-grained reactivity pairs well with Lottie's programmatic control API. Here's how to integrate them cleanly.
Setup
npm create solid@latest my-app
cd my-app
npm install @lottiefiles/dotlottie-web
Basic Component
import { onMount, onCleanup } from 'solid-js';
import { DotLottie } from '@lottiefiles/dotlottie-web';
function LottiePlayer({ src, loop = true, autoplay = true }) {
let canvasRef;
let dotLottie;
onMount(() => {
dotLottie = new DotLottie({
canvas: canvasRef,
src,
loop,
autoplay,
});
});
onCleanup(() => {
dotLottie?.destroy();
});
return <canvas ref={canvasRef} width="200" height="200" />;
}
export default LottiePlayer;
onMount and onCleanup replace React's useEffect with cleanup return. In SolidJS, refs are assigned directly — no useRef.
Reactive Controls
SolidJS signals integrate naturally with Lottie's playback API:
import { createSignal, onMount, onCleanup } from 'solid-js';
import { DotLottie } from '@lottiefiles/dotlottie-web';
function InteractiveLottie({ src }) {
let canvasRef;
let dotLottie;
const [playing, setPlaying] = createSignal(true);
const [speed, setSpeed] = createSignal(1);
onMount(() => {
dotLottie = new DotLottie({
canvas: canvasRef,
src,
loop: true,
autoplay: true,
});
});
const togglePlay = () => {
if (playing()) {
dotLottie.pause();
} else {
dotLottie.play();
}
setPlaying(p => !p);
};
const changeSpeed = (newSpeed) => {
dotLottie.setSpeed(newSpeed);
setSpeed(newSpeed);
};
onCleanup(() => dotLottie?.destroy());
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
<button onClick={togglePlay}>{playing() ? 'Pause' : 'Play'}</button>
<input
type="range"
min="0.5"
max="3"
step="0.5"
value={speed()}
onInput={(e) => changeSpeed(Number(e.target.value))}
/>
<span>{speed()}x</span>
</div>
);
}
Using lottie-web (SVG Renderer)
If you prefer SVG rendering or need addValueCallback for color changes:
npm install lottie-web
import lottie from 'lottie-web';
import { onMount, onCleanup } from 'solid-js';
function LottieSVG({ path }) {
let containerRef;
let anim;
onMount(() => {
anim = lottie.loadAnimation({
container: containerRef,
renderer: 'svg',
loop: true,
autoplay: true,
path,
});
});
onCleanup(() => anim?.destroy());
return <div ref={containerRef} style={{ width: '200px', height: '200px' }} />;
}
Lazy Loading
For animations below the fold, use an Intersection Observer:
import { createSignal, onMount, onCleanup } from 'solid-js';
import { DotLottie } from '@lottiefiles/dotlottie-web';
function LazyLottie({ src }) {
let canvasRef;
let wrapperRef;
let dotLottie;
const [loaded, setLoaded] = createSignal(false);
onMount(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting && !loaded()) {
setLoaded(true);
dotLottie = new DotLottie({
canvas: canvasRef,
src,
loop: true,
autoplay: true,
});
observer.disconnect();
}
},
{ threshold: 0.1 }
);
observer.observe(wrapperRef);
onCleanup(() => observer.disconnect());
});
onCleanup(() => dotLottie?.destroy());
return (
<div ref={wrapperRef} style={{ width: '200px', height: '200px' }}>
{loaded() && <canvas ref={canvasRef} width="200" height="200" />}
</div>
);
}
Preparing Animation Files
Before integrating:
- Preview at IconKing — check colors and bounds
- Edit colors directly in the browser — no After Effects needed
- Convert .json → .lottie at IconKing — saves ~75% file size
The .lottie format is the right choice for SolidJS projects targeting performance metrics.
Summary
| Pattern | SolidJS API | Notes |
|---|---|---|
| Mount animation | onMount |
Runs after DOM is ready |
| Cleanup | onCleanup |
Destroy to prevent memory leaks |
| Refs | let ref; <div ref={ref} |
Direct assignment, no useRef
|
| Reactive state | createSignal |
Connect to Lottie playback API |
Top comments (0)