19 C
New York
Monday, November 18, 2024

Methods to Create a Gooey Search Interplay with Framer Movement and React


I’ve been desperate to create one thing with the Gooey impact for some time. Whereas a lot of our friends on X have been experimenting with it, I wished to use it to a extra sensible element. Not too long ago, I stumbled upon a video showcasing dynamic island animations, which sparked my inspiration. Impressed by this, I made a decision to create a search bar—a small but gratifying interplay.

The Gooey Impact

First, we create the element for the Gooey impact from Lucas Bebber. I achieved the impact I wished by altering the alpha channel information within the values matrix.

const GooeyFilter = () => {
  return (
    <svg aria-hidden="true">
      <defs>
        <filter id="goo-effect">
          <feGaussianBlur in="SourceGraphic" stdDeviation="5" end result="blur" />
          <feColorMatrix
            in="blur"
            kind="matrix"
            values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -15"
            end result="goo"
          />
          <feComposite in="SourceGraphic" in2="goo" operator="atop" />
        </filter>
      </defs>
    </svg>
  );
};

export default GooeyFilter;
(Default and customized values)

Making use of the Impact

After creating the filter impact in our primary element, we apply this SVG filter to the mum or dad aspect via CSS.

<div className="wrapper"> 
   <GooeyFilter />
</div>

Framer Movement Integration

Up up to now, the method has been easy. Now, let’s add the essential ending touches with Framer Movement. With the SVG filter now lively, it’s able to be utilized to our transferring components, bringing the gooey impact to life.

We are going to use 4 totally different states to handle the search bar:

const [state, setState] = useState({
    step: 1, // Signifies the stage of the search course of 1: Preliminary state - 2: Search subject activated 
    searchData: [], // Comprises the outcomes of the search course of
    searchText: "", // Shops the search textual content 
    isLoading: false, // Used to point out a loading icon when loading search outcomes
  });

The code employs a nested construction of AnimatePresence elements. The outer layer manages the collective show of all outcomes, whereas the inside layer handles the person animation of every search end result.

<AnimatePresence mode="popLayout">
  <movement.div
    key="search-text-wrapper"
    className="search-results"
    function="listbox"
    aria-label="Search outcomes"
    exit={{ scale: 0, opacity: 0 }}
    transition={{
      delay: isUnsupported ? 0.5 : 1.25,
      length: 0.5,
    }}
  >
    <AnimatePresence mode="popLayout">
      {state.searchData.map((merchandise, index) => (
        <movement.div
          key={merchandise}
          whileHover={{ scale: 1.02, transition: { length: 0.2 } }}
          variants={getResultItemVariants(index, isUnsupported)}
          preliminary="preliminary"
          animate="animate"
          exit="exit"
          transition={getResultItemTransition(index, isUnsupported)}
          className="search-result"
          function="possibility"
        >
          <div className="search-result-title">
            <InfoIcon index={index} />
            <movement.span
              preliminary={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              transition={{ delay: index * 0.12 + 0.3 }}
            >
              {merchandise}
            </movement.span>
          </div>
        </movement.div>
      ))}
    </AnimatePresence>
  </movement.div>
</AnimatePresence>;

getResultItemVariants:

  • exit: On exit, gadgets transfer barely upward (y: -4) until isUnsupported is true, creating the phantasm of merging with the search bar.

getResultItemTransition:

  • length and delay: Every merchandise has a transition length of 0.75 seconds and a delay calculated by its index (index * 0.12) to realize sequential animations.
  • kind and bounce: A spring animation with a bounce impact (0.35) is used for clean motion.
  • filter: The filter property has easeInOut easing utilized to keep away from warnings within the spring calculation, as spring isn’t suitable with filter blur results.
const getResultItemVariants = (index, isUnsupported) => ({
  preliminary: {
    y: 0,
    scale: 0.3,
    filter: isUnsupported ? "none" : "blur(10px)",
  },
  animate: {
    y: (index + 1) * 50,
    scale: 1,
    filter: "blur(0px)",
  },
  exit: {
    y: isUnsupported ? 0 : -4,
    scale: 0.8,
    shade: "#000000",
  },
});

const getResultItemTransition = (index) => ({
  length: 0.75,
  delay: index * 0.12,
  kind: "spring",
  bounce: 0.35,
  exit: { length: index * 0.1 },
  filter: { ease: "easeInOut" },
});

And that’s it! That is the end result:

Safari Compatibility Challenges

We noticed the isUnsupported boolean within the code. This boolean was added by necessity. WebKit has some restrictions on SVG filters. It hasn’t been fastened for a very long time, though some customers have submitted bug stories.

isUnsupported contains some fixes to animations for Safari.

Wrapping It Up

I hope this tutorial sparked your creativity and impressed you to attempt the Gooey impact in your individual initiatives. It’s a enjoyable and visually fascinating approach so as to add some character to easy elements. Thanks for following alongside—blissful coding!



Supply hyperlink

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles