Implementation
Embed Lottie in HTML, React, Next.js, Webflow, and WordPress
23 September 2026
The deliverable is usually a `.json` (Bodymovin) or a `.lottie` bundle. Your page still needs a player. This page is the short handoff I attach to custom Lottie work: HTML, React, Next.js, Webflow, and WordPress — then the decisions that keep it from fighting the rest of the front end.
Plain HTML
Use `lottie-web` when you control the markup. Host the JSON next to the page (or on your CDN) and start the player after the container exists.
<div id="hero-lottie" style="width: min(100%, 480px)"></div>
<script src="https://unpkg.com/lottie-web@5.12.2/build/player/lottie.min.js"></script>
<script>
lottie.loadAnimation({
container: document.getElementById("hero-lottie"),
renderer: "svg",
loop: true,
autoplay: true,
path: "/animations/hero.json",
});
</script>For a no-build embed, Webflow and some CMSs also accept the LottieFiles player element. Same rule: one autoplay above the fold; lazy-load the rest. Pause when `prefers-reduced-motion: reduce`.
const motion = window.matchMedia("(prefers-reduced-motion: reduce)");
if (motion.matches) {
anim.pause();
anim.goToAndStop(0, true);
}React
`lottie-react` wraps `lottie-web`. Keep the player in a client component and import the JSON as a module (or fetch it if the file is large and should be cached separately).
"use client";
import Lottie from "lottie-react";
import hero from "./hero.json";
export function HeroLottie() {
return (
<Lottie
animationData={hero}
loop
autoplay
rendererSettings={{ preserveAspectRatio: "xMidYMid meet" }}
/>
);
}Next.js
App Router: the player must be a client component. Dynamic-import it so the Lottie runtime is not in the first server HTML. Put the JSON in `public/animations/` if you want a cacheable URL instead of bundling it into the JS chunk.
"use client";
import dynamic from "next/dynamic";
import hero from "./hero.json";
const Lottie = dynamic(() => import("lottie-react"), { ssr: false });
export function HeroLottie() {
return <Lottie animationData={hero} loop autoplay />;
}Lazy below the fold: do not import the player until the section is near the viewport (`IntersectionObserver`, or a small `WhenVisible` wrapper). That is the same pattern this site uses so archive demos do not compete with the hero.
Webflow
- Add a Lottie element (or an embed if you use a custom player).
- Upload the `.json` in the element settings. Turn loop on for UI/hero loops; leave it off for a one-shot logo.
- Set the animation to play when scrolled into view for anything that is not the first screen.
- Give the element a max width so a 1200 viewBox does not force a huge layout on mobile.
If the JSON is large, ask for a dotLottie (`.lottie`) when your embed supports it — same motion, smaller transfer. Webflow’s built-in Lottie control is JSON-first; confirm before you rely on `.lottie`.
WordPress
WordPress has no Lottie block in core. You either enqueue a player in the theme, drop HTML in a Custom HTML block, or use a plugin that wraps the same player. Two WordPress-specific gotchas: the Media Library often rejects `.json`, and a page builder will happily mount several autoplaying players.
- Host the file where the server will serve it: theme (`/wp-content/themes/your-theme/animations/hero.json`), a CDN, or allow `application/json` uploads if you must keep it in Media Library.
- Enqueue `lottie-web` (or the LottieFiles player) once in the theme/`functions.php` — do not paste a new `<script src>` on every post.
- In the editor, add a Custom HTML block with a container and a small init script, or a Gutenberg block from a Lottie plugin if the site already uses one.
- Give the container a max width. Lazy-load anything below the fold. One autoplay hero is enough.
add_action("wp_enqueue_scripts", function () {
wp_enqueue_script(
"lottie-web",
"https://unpkg.com/lottie-web@5.12.2/build/player/lottie.min.js",
[],
"5.12.2",
true
);
});<!-- Custom HTML block -->
<div id="hero-lottie" style="width:min(100%,480px)"></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
if (!window.lottie) return;
lottie.loadAnimation({
container: document.getElementById("hero-lottie"),
renderer: "svg",
loop: true,
autoplay: true,
path: "/wp-content/themes/your-theme/animations/hero.json",
});
});
</script>Elementor, Oxygen, and similar builders: use their HTML/embed widget with the same snippet, or a Lottie widget if they ship one. Do not upload the JSON as a “media file” unless you have already allowed the mime type — otherwise WordPress stores it nowhere useful. A plugin from LottieFiles is fine when the team does not want theme code; the file and lazy-load rules stay the same.
Renderer and fallback
- SVG renderer — default for UI. Layers stay in the DOM; you can tint or hook a class if the export is clean.
- Canvas renderer — often smoother for a busy hero. Harder to restyle in CSS.
- Native SVG (no Lottie player) — best for a short CSS/`<animate>` loop when you need DOM control and almost no JS. See SVG animation.
If you want the file built for your stack — size target, renderer, and a note in the brief — send the moment and a gallery reference. The optimize guide is the performance half of the same handoff.