Docs/Guides/Variants

Variants

A variant is a named animation state. Define a map, pass it to motion.* with variants, then drive the tree by passing a label or label array to animate, initial, exit, whileHover, and related props.

variants
variants-basic.tsxOpen ↗
import { motion } from 'motion-solidjs'
import { createSignal } from 'solid-js'

export const meta = {
  slug: 'variants-basic',
  title: 'Variants — basic',
  category: 'variants',
  description: 'Name your states and toggle between them by string.',
  tag: 'variants',
} as const

const box = {
  rest: { scale: 1, rotate: 0, borderRadius: '24%' },
  active: { scale: 1.2, rotate: 12, borderRadius: '50%' },
}

export default function VariantsBasic() {
  const [on, setOn] = createSignal(false)

  return (
    <motion.div
      onClick={() => setOn((v) => !v)}
      class="h-24 w-24 cursor-pointer bg-grad-violet shadow-glow"
      variants={box}
      animate={on() ? 'active' : 'rest'}
      transition={{ type: 'spring', stiffness: 260, damping: 18 }}
    />
  )
}

Orchestrate children

Variants propagate through motion children. Define matching labels on a parent and its children, then a single animate="open" on the parent drives both:

stagger
variants-stagger.tsxOpen ↗
import { motion, Variants } from 'motion-solidjs'
import { For } from 'solid-js'

export const meta = {
  slug: 'variants-stagger',
  title: 'Stagger children',
  category: 'variants',
  description: 'staggerChildren orchestrates a beautiful entrance.',
  tag: 'stagger',
} as const

const parent = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: { staggerChildren: 0.08, delayChildren: 0.1 },
  },
}

const child: Variants = {
  hidden: { opacity: 0, y: 20, scale: 0.9 },
  visible: {
    opacity: 1,
    y: 0,
    scale: 1,
    transition: { type: 'spring', stiffness: 360, damping: 24 },
  },
}

export default function VariantsStagger() {
  return (
    <motion.ul class="flex gap-2" variants={parent} initial="hidden" animate="visible">
      <For each={[0, 1, 2, 3, 4]}>
        {(i) => (
          <motion.li
            class="h-10 w-10 rounded-xl bg-grad-mint"
            style={{ 'background-position': `${i * 25}%` }}
            variants={child}
          />
        )}
      </For>
    </motion.ul>
  )
}

Dynamic variants

Variants can be functions of a custom prop:

custom
variants-dynamic.tsxOpen ↗
import { motion } from 'motion-solidjs'
import type { Variants } from 'motion-solidjs'
import { For } from 'solid-js'

export const meta = {
  slug: 'variants-dynamic',
  title: 'Dynamic variants',
  category: 'variants',
  description: 'Variants can be functions that receive a per-item custom value.',
  tag: 'custom',
} as const

const bar: Variants = {
  hidden: { scaleY: 0.05, opacity: 0.3 },
  visible: (custom: number) => ({
    scaleY: custom,
    opacity: 1,
    transition: {
      type: 'spring',
      stiffness: 220,
      damping: 14,
      delay: custom * 0.15,
    },
  }),
}

export default function VariantsDynamic() {
  return (
    <motion.div class="flex h-32 items-end gap-2" initial="hidden" animate="visible">
      <For each={[0.3, 0.8, 0.5, 1, 0.7, 0.4]}>
        {(h) => (
          <motion.div
            class="w-5 origin-bottom rounded-md bg-grad-rose"
            style={{ height: '100%' }}
            variants={bar}
            custom={h}
          />
        )}
      </For>
    </motion.div>
  )
}