Microinteractions

Elevate UX with Framer Motion

@vilvaathibanpb

About Me

  • Senior Full Stack Engineer
  • Omio, Berlin
  • Platform engineering
  • Inconsistent Blogger and Youtuber
  • Love to Teach, Travel and Eat

Agenda

  • Micro Interactions & their structure (theory)
  • Framer-motion & APIs (with demos)
  • Incorporate Micro Interactions using Framer-motion (live code)
  • Where to use/not use
  • Q/A

What is Micro-Interaction?

Micro Interactions

Micro-interactions are small, subtle, and often overlooked design elements that enhance user experience.

Life cycle of Micro Interactions

Trigger

Rules

Feedback

Loop and Mode

Example

Trigger

Rules

Feedback

Loop and Mode

Role in UX

  • Feedback
  • User Engagement
  • Enhancing Usability
  • Emotional Connection
  • Branding
  • Mobile and Responsiveness

What is Framer Motion

npm install framer-motion

How it works internally?

When we create an animation with framer motion:


1. Create motion values (MV) internally

2. Track current value & velocity in MV

3. Use MV to calculate the next step of the animation
4. These happen outside the React render cycle
 

Framer Motion API

Three parts of Framer Animations

1. Initial

 

2. Target

 

3. Transition

<motion>

Example

return (
    <h1 className="title">
        Welcome to FrontMania
    </h1>
)

Convert to motion

return (
    <motion.h1 className="title">
        Welcome to FrontMania
    </motion.h1>
)

Add animation stages

return (
    <motion.h1 
    	initial={{ opacity: 0}} 
        animate={{ opacity: 1 }} 
        className="title"
    >
        Welcome to FrontMania
    </motion.h1>
)

Add transition

return (
    <motion.h1 
    	initial={{ opacity: 0}} 
        animate={{ opacity: 1 }} 
        transition={{ duration: 2}} 
        className="title"
    >
        Welcome to FrontMania
    </motion.h1>
)

Keyframes

return (
    <motion.h1 
        animate={{ scale: [0.8, 1, 1.2, 0.9, 1.1, 1] }} 
        transition={{ duration: 2}} 
        className="title"
    >
        Welcome to FrontMania
    </motion.h1>
)

Variants

const h1Variant = {
  initial: { opacity: 0 },
  final: { opacity: 1 },
};

const spanVariant = {
  initial: { opacity: 0 },
  final: { opacity: 1, transition: { duration: 5 } },
};

  return (
    <motion.h1
      initial="initial"
      animate="final"
      transition={{ duration: 2 }}
      variants={h1Variant}
      className="title"
    >
      Welcome to
      <motion.span variants={spanVariant}>
        FrontMania
      </motion.span>
    </motion.h1>
  );

Variants

<AnimatePresence />

Simple Todo

function Todo({ todo, index, removeTodo }) {
  return (
    <div
      className="todo"
      onClick={() => removeTodo(index)}
    >
      {todo.text}
    </div>
  );
}


// List
{todos.map((todo, index) => (
          <Todo
            key={index}
            index={index}
            todo={todo}
            completeTodo={completeTodo}
            removeTodo={removeTodo}
          />
        ))}

Simple Todo

function Todo({ todo, index, removeTodo }) {
  return (
    <motion.div
      key={index}
      initial={{ x: -100, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      exit={{ x: 100, opacity: 0 }}
      className="todo"
      onClick={() => removeTodo(index)}
    >
      {todo.text}
    </motion.div>
  );
}


// List
 <AnimatePresence>
          {todos.map((todo, index) => (
            <Todo
              key={todo.text}
              index={index}
              todo={todo}
              completeTodo={completeTodo}
              removeTodo={removeTodo}
            />
          ))}
</AnimatePresence>

Guestures

  • Hover
  • Drag
  • Tap
  • Pan

Hover

function Todo({ todo, index, removeTodo }) {
  return (
    <motion.div
      key={index}
      initial={{ x: -100, opacity: 0 }}
      animate={{ x: 0, opacity: 1 }}
      exit={{ x: 100, opacity: 0 }}
      whileHover={{ scale: 1.2}}
      className="todo"
      onClick={() => removeTodo(index)}
    >
      {todo.text}
    </motion.div>
  );
}


// List
 <AnimatePresence>
          {todos.map((todo, index) => (
            <Todo
              key={todo.text}
              index={index}
              todo={todo}
              completeTodo={completeTodo}
              removeTodo={removeTodo}
            />
          ))}
</AnimatePresence>

ReOrder

        <Reorder.Group axis="y" values={todos} onReorder={setTodos}>
          {todos.map((todo, index) => (
            <Reorder.Item key={todo} value={todo} className="todo">
              {todo}
            </Reorder.Item>
          ))}
        </Reorder.Group>

Layout Animation

<LayoutGroup>
      <motion.div layout>
      <motion.div layout>
      <motion.div layout>
<LayoutGroup>

Some useful hooks

  • useScroll
  • useMotionValue
  • useAnimate
  • useSpring
  • useWillChange
  • useDragControl
  • useInView

Live Demo

When not to use Micro interactions

  • Reduced motion
  • Accessibility
  • Data/Battery
  • Overuse

GPU

  • transform
  • opacity
  • clipPath
  • filter
  • background-color
  • motion with `onUpdate`.
  • motion value as style.
  • repeatDelay
  • repeatType - "mirror".
  • damping - 0

vs

CPU

QA Time

Thank you for being an wonderful audience

Microinteractions

By Vilva Athiban

Microinteractions

  • 96