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

  1. Add a Lottie element (or an embed if you use a custom player).
  2. Upload the `.json` in the element settings. Turn loop on for UI/hero loops; leave it off for a one-shot logo.
  3. Set the animation to play when scrolled into view for anything that is not the first screen.
  4. 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.

  1. 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.
  2. Enqueue `lottie-web` (or the LottieFiles player) once in the theme/`functions.php` — do not paste a new `<script src>` on every post.
  3. 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.
  4. 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.