Beta Status
This library is still in early beta and the API is subject to change and may get daily breaking changes. The documentaton may not be up to date with the latest features and include missing or outdated information. You can always create an issue on GitHub or even better a pull request to fix the documentation or add new features.
Variants
Variants let you name animation targets and orchestrate them across initial, animate, exit, and while* props. They enable reusable animations and parent-child coordination.
Defining Variants
import { motion } from "motion-solid";
const card = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.35 },
},
exit: {
opacity: 0,
y: -20,
transition: { duration: 0.2 },
},
};
<motion.div variants={card} initial="hidden" animate="visible" exit="exit" />;
Props That Accept Variants
These props accept variant labels: initial, animate, exit, whileHover, whileTap, whileFocus, whileInView, whileDrag.
Multiple Labels
Pass an array to merge variants in order:
const card = {
visible: { opacity: 1, y: 0 },
highlighted: { scale: 1.05, "box-shadow": "0 4px 12px rgba(0,0,0,0.1)" },
};
<motion.div variants={card} animate={["visible", "highlighted"]} />;
Later variants override earlier ones for conflicting properties.
Function Variants
Variants can be functions that receive (custom, current, velocity):
const item = {
hidden: { opacity: 0 },
visible: (custom: number) => ({
opacity: 1,
transition: { delay: custom * 0.1 },
}),
};
<For each={items()}>
{(item, i) => (
<motion.div
variants={variants}
custom={i()}
initial="hidden"
animate="visible"
/>
)}
</For>;
Function Parameters
custom- Value fromcustomprop or AnimatePresencecurrent- Current motion valuesvelocity- Current velocity of motion values
Returning Labels
Function variants can return a label string, resolved against the same variants map:
const menu = {
open: { opacity: 1 },
closed: { opacity: 0 },
toggle: (isOpen: boolean) => (isOpen ? "open" : "closed"),
};
<motion.div variants={menu} animate="toggle" custom={isOpen()} />;
Orchestration
Parent variants can coordinate child animations:
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
when: "beforeChildren",
staggerChildren: 0.1,
delayChildren: 0.2,
},
},
};
const item = {
hidden: { opacity: 0, y: 10 },
show: { opacity: 1, y: 0 },
};
<motion.ul variants={container} initial="hidden" animate="show">
<For each={items()}>{() => <motion.li variants={item} />}</For>
</motion.ul>;
Orchestration options:
when: "beforeChildren"- Parent finishes before children startwhen: "afterChildren"- Children finish before parent startsdelayChildren- Base delay before children startstaggerChildren- Delay between each childstaggerDirection-1(forward) or-1(reverse)
Advanced Staggering
Use the stagger function for custom patterns:
import { stagger } from "motion-solid";
const container = {
show: {
transition: {
delayChildren: stagger(0.08, {
from: "center", // or "first", "last", or index
}),
},
},
};
Inheritance
Children inherit variant labels from ancestors by default:
<motion.ul variants={list} initial="hidden" animate="show">
{/* Inherits "hidden" and "show" */}
<motion.li variants={item} />
{/* Uses its own "peek" instead of inherited "show" */}
<motion.li variants={item} animate="peek" inherit={false} />
</motion.ul>
Set inherit={false} to opt out of parent variant resolution.
Example: Staggered List
import { motion } from "motion-solid";
import { For } from "solid-js";
const container = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.05,
},
},
};
const item = {
hidden: { opacity: 0, x: -20 },
visible: { opacity: 1, x: 0 },
};
function StaggeredList(props: { items: string[] }) {
return (
<motion.ul variants={container} initial="hidden" animate="visible">
<For each={props.items}>
{(text) => <motion.li variants={item}>{text}</motion.li>}
</For>
</motion.ul>
);
}
Example: Expandable Card
const card = {
collapsed: {
height: 60,
transition: { type: "spring", stiffness: 300, damping: 30 },
},
expanded: (custom: { height: number }) => ({
height: custom.height,
transition: { type: "spring", stiffness: 300, damping: 30 },
}),
};
function ExpandableCard(props: { content: string }) {
const [expanded, setExpanded] = createSignal(false);
return (
<motion.div
variants={card}
initial="collapsed"
animate={expanded() ? "expanded" : "collapsed"}
custom={{ height: expanded() ? 200 : 60 }}
onClick={() => setExpanded((e) => !e)}
>
{props.content}
</motion.div>
);
}