Making Sense of react-spring

Animation is one of the trickier things to get right with React. In this post, I’ll try to provide the introduction to react-spring I wish I had when I first started out, then dive into some interesting use cases. While react-spring isn’t the only animation library for React, it’s one of the more popular (and better) ones.

I’ll be using the newest version 9 which, as of this writing, is in release candidate status. If it’s not fully released by the time you read this, be sure to install it with react-spring@next. From on what I’ve seen and from what the lead maintainer has told me, the code is incredibly stable. The only issue I’ve seen is a slight bug when used with concurrent mode, which can be tracked in the GitHub repo.

react-spring redux

Before we get to some interesting application use cases, let’s take a whirlwind intro. We’ll cover springs, height animation, and then transitions. I’ll have a working demo at the end of this section, so don’t worry if things get a little confusing along the way. 

springs

Let’s consider the canonical “Hello world” of animation: fading content in and out. Let’s stop for a moment and consider how we’d switch opacity on and off without any kind of animation. It’d look something like this:

export default function App() {
  const [showing, setShowing] = useState(false);
  return (
    <div>
      <div style={{ opacity: showing ? 1 : 0 }}>
        This content will fade in and fade out
      </div>
      <button onClick={() => setShowing(val => !val)}>Toggle</button>
      <hr />
    </div>
  );
}

Easy, but boring. How do we animate the changing opacity? Wouldn’t it be nice if we could declaratively set the opacity we want based on state, like we do above, except have those values animate smoothly? That’s what react-spring does. Think of react-spring as our middle-man that launders our changing style values, so it can produce the smooth transition between animating values we want. Like this:

const [showA, setShowA] = useState(false);


const fadeStyles = useSpring({
  config: { ...config.stiff },
  from: { opacity: 0 },
  to: {
    opacity: showA ? 1 : 0
  }
});

We specify our initial style values with from, and we specify the current value in the to section, based on our current state. The return value, fadeStyles, contains the actual style values we apply to our content. There’s just one last thing we need…

You might think you could just do this:

<div style={fadeStyles}>

…and be done. But instead of using a regular div, we need to use a react-spring div that’s created from the animated export. That may sound confusing, but all it really means is this:

<animated.div style={fadeStyles}>

And that’s it. 

animating height 

Depending on what we’re animating, we may want the content to slide up and down, from a zero height to its full size, so the surrounding contents adjust and flow smoothly into place. You might wish that we could just copy the above, with height going from zero to auto, but alas, you can’t animate to auto height. That neither works with vanilla CSS, nor with react-spring. Instead, we need to know the actual height of our contents, and specify that in the to section of our spring.

We need to have the height of any arbitrary content on the fly so we can pass that value to react-spring. It turns out the web platform has something specifically designed for that: a ResizeObserver. And the support is actually pretty good! Since we’re using React, we’ll of course wrap that usage in a hook. Here’s what mine looks like:

export function useHeight({ on = true /* no value means on */ } = {} as any) {
  const ref = useRef<any>();
  const [height, set] = useState(0);
  const heightRef = useRef(height);
  const [ro] = useState(
    () =>
      new ResizeObserver(packet => {
        if (ref.current && heightRef.current !== ref.current.offsetHeight) {
          heightRef.current = ref.current.offsetHeight;
          set(ref.current.offsetHeight);
        }
      })
  );
  useLayoutEffect(() => {
    if (on && ref.current) {
      set(ref.current.offsetHeight);
      ro.observe(ref.current, {});
    }
    return () => ro.disconnect();
  }, [on, ref.current]);
  return [ref, height as any];
}

We can optionally provide an on value that switches measuring on and off (which will come in handy later). When on is true, we tell our ResizeObserver to observe out content. We return a ref that needs to be applied to whatever content we want measured, as well as the current height.

Let’s see it in action.

const [heightRef, height] = useHeight();
const slideInStyles = useSpring({
  config: { ...config.stiff },
  from: { opacity: 0, height: 0 },
  to: {
    opacity: showB ? 1 : 0,
    height: showB ? height : 0
  }
});

useHeight gives us a ref and a height value of the content we’re measuring, which we pass along to our spring. Then we apply the ref and apply the height styles.

<animated.div style={{ ...slideInStyles, overflow: "hidden" }}>
  <div ref={heightRef}>
    This content will fade in and fade out with sliding
  </div>
</animated.div>

Oh, and don’t forget to add overflow: hidden to the container. That allows us to properly container our adjusting height values.

animating transitions

Lastly, let’s look at adding and removing animating items to and from the DOM. We already know how to animate changing values of an item that exists and is staying in the DOM, but to animate the adding, or removing of items, we need a new hook: useTransition.

If you’ve used react-spring before, this is one of the few places where version 9 has some big changes to its API. Let’s take a look.

In order to animate a list of items, like this:

const [list, setList] = useState([]);

…we’ll declare our transition function like this:

const listTransitions = useTransition(list, {
  config: config.gentle,
  from: { opacity: 0, transform: "translate3d(-25%, 0px, 0px)" },
  enter: { opacity: 1, transform: "translate3d(0%, 0px, 0px)" },
  leave: { opacity: 0, height: 0, transform: "translate3d(25%, 0px, 0px)" },
  keys: list.map((item, index) => index)
});

As I alluded earlier, the return value, listTransitions, is a function. react-spring is tracking the list array, keeping tabs on the items which are added and removed. We call the listTransitions function, provide a callback accepting a single styles object and a single item, and react-spring will call it for each item in the list with the right styles, based on whether it’s newly added, newly removed, or just sitting in the list.

Note the keys section: This allows us to tell react-spring how to identify objects in the list. In this case, I decided to tell react-spring that an item’s index in the array uniquely defines that item. Normally this would be a terrible idea, but for now, it lets us see the feature in action. In the demo below, the “Add item” button adds an item to the end of the list when clicked, and the “Remove last item” button removes the most recently added item from the list. So, if you type in the input box then quickly hit the add button then the remove button, you’ll see the same item smoothly begin to enter, and then immediately, from whatever stage in the animation it’s at, begin to leave. Conversely, if you add an item, then quickly hit the remove button and the add button, the same item will begin to slide off, then abruptly stop in place, and slide right back to where it was.

Here’s that demo

Whew, that was a ton of words! Here’s a working demo, showing everything we just covered in action.

Odds and Ends

Did you notice how, when you slide down the content in the demo, it sort of bounces into place, like… a spring? That’s where the name comes from: react-spring interpolates our changing values using spring physics. It doesn’t simply chop the value changing into N equal deltas that it applies over N equal delays. Instead, it uses a more sophisticated algorithm that produces that spring-like effect, which will appear more natural.

The spring algorithm is fully configurable, and it comes with a number of presets you can take off the shelf — the demo above uses the stiff, and gentle presets. See the docs for more info.

Note also how I’m animating values inside of translate3d values. As you can see, the syntax isn’t the most terse, and so react-spring provides some shortcuts. There’s documentation on this, but for the remainder of this post I’ll continue to use the full, non-shortcut syntax for the sake of keeping things as clear as possible. 

I’ll close this section by calling attention to the fact that, when you slide the content up in the demo above, you’ll likely see the content underneath it get a little jumpy at the very end. This is a result of that same bouncing effect. It looks sharp when the content bounces down and into position, but less so when we’re sliding the content up. Stay tuned to see how we can switch it off. (Spoiler, it’s the clamp property).

A few things to consider with these sandboxes

Code Sandbox uses hot reloading. As you change the code, changes are usually reflected immediately. This is cool, but can wreck havoc on animations. If you start tinkering, and then see weird, ostensibly incorrect behavior, try refreshing the sandbox.

The other sandboxes in this post will make use of a modal. For reasons I haven’t quite been able to figure out, when the modal is open, you won’t be able to modify any code — the modal refuses to give up focus. So, be sure to close the modal before attempting any changes. 

Now let’s build something real

Those are the basic building blocks of react-spring. Let’s use them to build something more interesting. You might think, given everything above, that react-spring is pretty simple to use. Unfortunately, in practice, it can be tricky to figure out some subtle things you need to get right. The rest of this post will dive into many of these details. 

Prior blog posts I’ve written have been in some way related to my booklist side project. This one will be no different — it’s not an obsession, it’s just that that project happens to have a publicly-available GraphQL endpoint, and plenty of existing code that be can leveraged, making it an obvious target.

Let’s build a UI that allows you to open a modal and search for books. When the results come in, you can add them to a running list of selected books that display beneath the modal. When you’re done, you can close the modal and click a button to find books similar to the selection.

We’ll start with a functioning UI then animate the pieces step by step, including interactive demos along the way.

If you’re really eager to see what the final result will look like, or you’re already familiar with react-spring and want to see if I’m covering anything you don’t already know, here it is (it won’t win any design awards, I’m well aware). The rest of this post will cover the journey getting to that end state, step by step.

Animating our modal

Let’s start with our modal. Before we start adding any kind of data, let’s get our modal animating nicely.  Here’s what a basic, un-animated modal looks like. I’m using Ryan Florence’s Reach UI (specifically the modal component), but the idea will be the same no matter what you use to build your modal. We’d like to get our backdrop to fade in, and also transition our modal content.

Since a modal is conditionally rendered based on some sort of “open” property, we’ll use the useTransition hook. I was already wrapping the Reach UI modal with my own modal component, and rendering either nothing, or the actual modal based on the isOpen property. We just need to go through the transition hook to get it animating.

Here’s what the transition hook looks like:

const modalTransition = useTransition(!!isOpen, {
  config: isOpen ? { ...config.stiff } : { duration: 150 },
  from: { opacity: 0, transform: `translate3d(0px, -10px, 0px)` },
  enter: { opacity: 1, transform: `translate3d(0px, 0px, 0px)` },
  leave: { opacity: 0, transform: `translate3d(0px, 10px, 0px)` }
});

There’s not too many surprises here. We want to fade things in and provide a slight vertical transition based on whether the modal is active or not. The odd piece is this:

config: isOpen ? { ...config.stiff } : { duration: 150 },

I want to only use spring physics if the modal is opening. The reason for this — at least in my experience — is when you close the modal, the backdrop takes too long to completely vanish, which leaves the underlying UI un-interactive for too long. So, when the modal opens, it’ll nicely bounce into place with spring physics, and when closed, it’ll quickly vanish in 150ms.

And, of course, we’ll render our content via the transition function our hook returns. Notice that I’m plucking the opacity style off of the styles object to apply to the backdrop, and then applying all the animating styles to the actual modal content.

return modalTransition(
  (styles, isOpen) =>
    isOpen && (
      <AnimatedDialogOverlay
        allowPinchZoom={true}
        initialFocusRef={focusRef}
        onDismiss={onHide}
        isOpen={isOpen}
        style={{ opacity: styles.opacity }}
      >
      <AnimatedDialogContent
        style={{
          border: "4px solid hsla(0, 0%, 0%, 0.5)",
          borderRadius: 10,
          maxWidth: "400px",
          ...styles
        }}
      >
        <div>
          <div>
            <StandardModalHeader caption={headerCaption} onHide={onHide} />
            {children}
          </div>
        </div>
      </AnimatedDialogContent>
    </AnimatedDialogOverlay>
  )
);

Base setup

Let’s start with the use case I described above. If you’re following along with the demos, here’s a full demo of everything working, but with zero animation. Open the modal, and search for anything (feel free to just hit Enter in the empty textbox). You should hit my GraphQL endpoint, and get back search results from my own personal library.

The rest of this post will focus on adding animations to the UI, which will give us a chance to see a before and after, and (hopefully) observe how much nicer some subtle, well-placed animations can make a UI. 

Animating the modal size

Let’s start with the modal itself. Open it and search for, say, “jefferson.” Notice how the modal abruptly becomes larger to accommodate the new content. Can we have the modal animate to larger (and smaller) sizes? Of course. Let’s dig out our trusty useHeight hook, and see what we can do.

Unfortunately, we can’t simply slap the height ref on a wrapper in our content, and then stick the height in a spring. If we did this, we’d see the modal slide into its initial size. We don’t want that; we want our fully formed modal to appear in the right size, and re-size from there.

What we want to do is wait for our modal content to be rendered in the DOM, then set our height ref, and switch on our useHeight hook, to start measuring. Oh, and we want our initial height to be set immediately, and not animate into place. It sounds like a lot, but it’s not as bad as it sounds.

Let’s start with this:

const [heightOn, setHeightOn] = useState(false);
const [sizingRef, contentHeight] = useHeight({ on: heightOn });
const uiReady = useRef(false);

We have some state for whether we’re measuring our modal’s height. This will be set to true when the modal is in the DOM. Then we call our useHeight hook with the on property, for whether we’re active. Lastly, some state to hold whether our UI is ready, and we can begin animating.

First things fist: how do we even know when our modal is actually rendered in the DOM? It turns out we can use a ref that lets us know. We’re used to doing <div ref={someRef} in React, but you can actually pass a function, which React will call with the DOM node after it’s rendered. Let’s define that function now.

const activateRef = ref => {
  sizingRef.current = ref;
  if (!heightOn) {
    setHeightOn(true);
  }
};

That sets our height ref and switches on our useHeight hook. We’re almost done!

Now how do we get that initial animation to not be immediate? The useSpring hook has two new properties we’ll look at now. It has an immediate property which tells it to make states changes immediate instead of animating them. It also has an onRest callback which fires when a state change finishes.

Let’s leverage both of them. Here’s what the final hook looks like:

const heightStyles = useSpring({
  immediate: !uiReady.current,
  config: { ...config.stiff },
  from: { height: 0 },
  to: { height: contentHeight },
  onRest: () => (uiReady.current = true)
});

Once any height change is completed, we set the uiReady ref to true. So long as it’s false, we tell react-spring to make immediate changes. So, when our modal first mounts, contentHeight is zero (useHeight will return zero if there’s nothing to measure) and the spring is just chilling, doing nothing. When the modal switches to open and actual content is rendered, our activateRef ref is called, our useHeight will switch on, we’ll get an actual height value for our contents, our spring will set it “immediately,” and, finally, the onRest callback will trigger, and future changes will be animated. Phew!

I should point out that if, in some alternate use case we did immediately have a correct height upon the first render, we’d be able to simplify the above hook to just this:

const heightStyles = useSpring({
  to: {
    height: contentHeight
  },
  config: config.stiff,
})

…which can actually be further simplified to this:

const heightStyles = useSpring({
  height: contentHeight,
  config: config.stiff,
})

Our hook would render initially with the correct height, and any changes to that value would be animated. But since our modal renders before it’s actually shown, we can’t avail ourselves to this simplification. 

Keen readers might wonder what happens when you close the modal. Well, the content will un-render and the height hook will just stick with the last reported height, though still “observing” a DOM node that’s no longer in the DOM. If you’re worried about that, feel free to clean things up better than I have here, perhaps with something like this:

useLayoutEffect(() => {
  if (!isOpen) {
    setHeightOn(false);
  }
}, [isOpen]);

That’ll cancel the ResizeObserver for that DOM node and fix the memory leak.

Animating the results

Next, let’s look at animating the changing of the results within the modal. If you run a few searches, you should see the results immediately swap in and out.

Take a look at the SearchBooksContent component in the searchBooks.js file. Right now, we have const booksObj = data?.allBooks; which plucks the appropriate result set off of the GraphQL response, and then later renders them.

{booksObj.Books.map(book => (
  <SearchResult
    key={book._id}
    book={book}
    selected={selectedBooksMap[book._id]}
    selectBook={selectBook}
    dispatch={props.dispatch}
  />
))}

As fresh results come back from our GraphQL endpoint, this object will change, so why not take advantage of that fact, and pass it to the useTransition hook from before, and get some transition animations defined.

const resultsTransition = useTransition(booksObj, {
  config: { ...config.default },
  from: {
    opacity: 0,
    position: "static",
    transform: "translate3d(0%, 0px, 0px)"
  },
  enter: {
    opacity: 1,
    position: "static",
    transform: "translate3d(0%, 0px, 0px)"
  },
  leave: {
    opacity: 0,
    position: "absolute",
    transform: "translate3d(90%, 0px, 0px)"
  }
});

Note the change from position: static to position: absolute. An outgoing result set with absolute positioning has no effect on its parent’s height, which is what we want. Our parent will size to the new contents and, of course, our modal will nicely animate to the new size based on the work we did above.

As before, we’ll use our transition function to render our content:

<div className="overlay-holder">
  {resultsTransition((styles, booksObj) =>
    booksObj?.Books?.length ? (
      <animated.div style={styles}>
        {booksObj.Books.map(book => (
          <SearchResult
            key={book._id}
            book={book}
            selected={selectedBooksMap[book._id]}
            selectBook={selectBook}
            dispatch={props.dispatch}
          />
        ))}
      </animated.div>
    ) : null
  )}

Now new result sets will fade in, while outgoing sets of results will fade (and slightly slide) out to give the user an extra cue that things have changed.

Of course, we also want to animate any messaging, such as when there’s no results, or when the user has selected everything in the result set. The code for that is pretty repetitive with everything else in here, and since this post is already getting long, I’ll leave the code in the demo.

Animating selected books (out)

Right now, selecting a book instantly and abruptly vanishes it from the list. Let’s apply our usual fade out while sliding it out to the right. And as the item is sliding out to the right (via transform), we probably want its height to animate to zero so the list can smoothly adjust to the exiting item, rather than have it slide out, leaving behind an the empty box, which then immediately disappears.

By now, you probably think this is easy. You’re expecting something like this:

const SearchResult = props => {
  let { book, selectBook, selected } = props;


  const initiallySelected = useRef(selected);
  const [sizingRef, currentHeight] = useHeight();


  const heightStyles = useSpring({
    config: { ...config.stiff, clamp: true },
    from: {
      opacity: initiallySelected.current ? 0 : 1,
      height: initiallySelected.current ? 0 : currentHeight,
      transform: "translate3d(0%, 0px, 0px)"
    },
    to: {
      opacity: selected ? 0 : 1,
      height: selected ? 0 : currentHeight,
      transform: `translate3d(${selected ? "25%" : "0%"},0px,0px)`
    }
  }); 

This uses our trusted useHeight hook to measure our content, using the selected value to animate the item that’s leaving. We’re tracking the selected prop and animating to, or starting with, a height of 0 if it’s already selected, rather than simply removing the item and using a transition. This allows different result sets that have the same book to correctly decline to display it, if it’s selected.

This code does work. Give it a try in this demo.

But there’s a rub. If you select most of the books in a result set, there will be a kind of bouncy animation chain as you continue selecting. The book starts animating out of the list, and then the modal’s height itself starts trailing behind.

This looks goofy in my opinion, so let’s see what we can do about it. 

We’ve already seen how we can use the immediate property to turn off all spring animations. We’ve also seen the onRest callback fire when an animation finishes, and I’m sure you won’t be surprised to learn there’s an onStart callback which does what you’d expect. Let’s use those pieces to allow the content inside our modal to “turn off” the modal’s height animation when the content itself is animating heights.

First, we’ll add some state to our modal that switches animation on and off.

const animatModalSizing = useRef(true);
const modalSizingPacket = useMemo(() => {
  return {
    disable() {
      animatModalSizing.current = false;
    },
    enable() {
      animatModalSizing.current = true;
    }
  };
}, []);

Now, let’s tie it into our transition from before.

const heightStyles = useSpring({
  immediate: !uiReady.current || !animatModalSizing.current,
  config: { ...config.stiff },
  from: { height: 0 },
  to: { height: contentHeight },
  onRest: () => (uiReady.current = true)
});

Great. Now how do we get that modalSizingPacket down to our content, so whatever we’re rendering can actually switch off the modal’s animation, when needed? Context of course! Let’s create a piece of context.

export const ModalSizingContext = createContext(null);

Then, we’ll wrap all of our modal’s content with it:

<ModalSizingContext.Provider value={modalSizingPacket}>

Now our SearchResult component can grab it:

const { enable: enableModalSizing, disable: disableModalSizing } = useContext(
  ModalSizingContext
);

…and tie it right into its spring:

const heightStyles = useSpring({
  config: { ...config.stiff, clamp: true },
  from: {
    opacity: initiallySelected.current ? 0 : 1,
    height: initiallySelected.current ? 0 : currentHeight,
    transform: "translate3d(0%, 0px, 0px)"
  },
  to: {
    opacity: selected ? 0 : 1,
    height: selected ? 0 : currentHeight,
    transform: `translate3d(${selected ? "25%" : "0%"},0px,0px)`
  },
  onStart() {
    if (uiReady.current) {
      disableModalSizing();
    }
  },
  onRest() {
    uiReady.current = true;
    setTimeout(() => {
      enableModalSizing();
    });
  }
});

Note the setTimeout at the very end. I’ve found it necessary to make sure the modal’s animation is truly shut off until everything’s settled.

I know that was a lot of code. If I moved too fast, be sure to check out the demo to see all this in action.

Animating selected books (in)

Let’s wrap this blog post up by animating the selected books that appear on the main screen, beneath the modal. Let’s have newly selected books fade in while sliding in from the left when selected, then slide out to the right while it’s height shrinks to zero when removed.

We’ll use a transition, but there already seems to be a problem because we need to account for each of the selected books needs to have its own, individual height. Previously, when we reached for useTransition, we’ve had a single from and to object that was applied to entering and exiting items.

Here, we’ll use an alternate form instead, allowing us to provide a function for the to object. It’s invoked with the actual animating item — a book object in this case — and we return the to object that contains the animating values. Additionally, we’ll keep track of a simple lookup object which maps each book’s ID to its height, and then tie that into our transition.

First, let’s create our map of height values:

const [displaySizes, setDisplaySizes] = useState({});
const setDisplaySize = useCallback(
  (_id, height) => {
    setDisplaySizes(displaySizes => ({ ...displaySizes, [_id]: height }));
  },
  [setDisplaySizes]
);

We’ll pass the setDisplaySizes update function to the SelectedBook component, and use it with useHeight to report back the actual height of each book.

const SelectedBook = props => {
  let { book, removeBook, styles, setDisplaySize } = props;
  const [ref, height] = useHeight();
  useLayoutEffect(() => {
    height && setDisplaySize(book._id, height);
  }, [height]);

Note how we check that the height value has been updated with an actual value before calling it. That’s so we don’t prematurely set the value to zero before setting the correct height, which would cause our content to animate down, rather than sliding in fully-formed. Instead, no height will initially be set, so our content will default to height: auto. When our hook fires, the actual height will set. When an item is removed, the height will animate down to zero, as it fades and slides out.

Here’s the transition hook:

const selectedBookTransitions = useTransition(selectedBooks, {
  config: book => ({
    ...config.stiff,
    clamp: !selectedBooksMap[book._id]
  }),
  from: { opacity: 0, transform: "translate3d(-25%, 0px, 0px)" },
  enter: book => ({
    opacity: 1,
    height: displaySizes[book._id],
    transform: "translate3d(0%, 0px, 0px)"
  }),
  update: book => ({ height: displaySizes[book._id] }),
  leave: { opacity: 0, height: 0, transform: "translate3d(25%, 0px, 0px)" }
});

Notice the update callback. It will adjust our content if any of the heights change. (You can force this in the demo by resizing the results pane after selecting a bunch of books.)

For a little icing on top of our cake, note how we’re conditionally setting the clamp property of our hook’s config. As content is animating in, we have clamp off, which produces a nice (at least in my opinion) bouncing effect. But when leaving, it animates down, but stays gone, without any of the jitteriness we saw before with clamping turned off.

Bonus: Simplifying the modal height animation while fixing a bug in the process

After finishing this post, I found a bug in the modal implementation where, if the modal height changes while it’s not shown, you’ll see the old, now incorrect height the next time you open the modal, followed by the modal animating to the correct height. To see what I mean, have a look at this update to the demo. You’ll notice new buttons to clear, or force results into the modal when it’s not visible. Open the modal, then close it, click the button to add results, and re-open it — you should see it awkwardly animate to the new, correct height.

Fixing this also allows us to simplify the code for the height animation from before. The problem is that our modal currently continues to render in the React component tree, even when not shown. The height hook is still “running,” only to be updated the next time the modal is shown, rendering the children. What if we moved the modal’s children to its own, dedicated component, and brought the height hook with it? That way, the hook and animation spring will only be render when the modal is shown, and can start with correct values. It’s less complicated than it seems. Right now our modal component has this:

<animated.div style={{ overflow: "hidden", ...heightStyles }}>
  <div style={{ padding: "10px" }} ref={activateRef}>
    <StandardModalHeader
      caption={headerCaption}
      onHide={onHide}
    />
    {children}
  </div>
</animated.div>

Let’s make a new component that renders this markup, including the needed hooks and refs:

const ModalContents = ({ header, contents, onHide, animatModalSizing }) => {
  const [sizingRef, contentHeight] = useHeight();
  const uiReady = useRef(false);

  const heightStyles = useSpring({
    immediate: !uiReady.current || !animatModalSizing.current,
    config: { ...config.stiff },
    from: { height: 0 },
    to: { height: contentHeight },
    onRest: () => (uiReady.current = true)
  });

  return (
    <animated.div style={{ overflow: "hidden", ...heightStyles }}>
      <div style={{ padding: "10px" }} ref={sizingRef}>
        <StandardModalHeader caption={header} onHide={onHide} />
        {contents}
      </div>
    </animated.div>
  );
};

This is a significant reduction in complexity compared to what we had before. We no longer have that activateRef function, and we no longer have the heightOn state that was set in activateRef. This component is only rendered by the modal if it’s being shown, which means we’re guaranteed to have content, so we can just add a regular ref to our div. Unfortunately, we do still need our uiReady state, since even now we don’t initially have our height on first render; that’s not available until the useHeight layout effect fires immediately after the first render finishes.

And, of course, this solves the bug from before. No matter what happens when the modal is closed, when it re-opens, this component will render anew, and our spring will start with a fresh value for uiReady.

Parting thoughts

If you’ve stuck with me all this way, thank you! I know this post was long, but I hope you found some value in it.

react-spring is an incredible tool for creating robust animations with React. It can be low-level at times, which can make it hard to figure out for non-trivial use cases. But it’s this low-level nature that makes it so flexible.


The post Making Sense of react-spring appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

How to Make a Monthly Calendar With Real Data

Have you ever seen a calendar on a webpage and thought, how the heck did they did that? For something like that, it might be natural to reach for a plugin, or even an embedded Google Calendar, but it’s actually a lot more straightforward to make one than you might think and only requires the trifecta of HTML, CSS and JavaScript. Let’s make one together!

I’ve set up a demo over at CodeSandbox so you can see what we’re aiming for.

Let’s first identify some requirements for what the calendar should do. It should:

  • Display a month grid for a given month
  • Display dates from the previous and next months to so the grid is always full
  • Indicate current date
  • Show the name of the currently selected month
  • Navigate to the previous and next month
  • Allow the user to navigate back to current month with a single click

Oh, and we’ll build this as a single page application that fetches calendar dates from Day.js, a super light utility library.

We’re going to shy away from choosing a specific framework to keep things easy. For this setup, I’m using Parcel for package management so I can write in Babel, bundle things up, and manage the one and only dependency for the project. Check out the package.json file over at CodeSandbox for specifics.

Step 1: Start with the basic markup and styles

Let’s start with creating a basic template for our calendar. This doesn’t need to be anything fancy. But it also should be done without resorting to tables.

We can outline our markup as three layers where we have:

  • A section for the calendar header. This will show the currently selected month and the elements responsible for paginating between months.
  • A section for the calendar grid header. Again, we’re not reaching form tables, but this would be sort of like a table header that holds a list containing the days of the week, starting with Monday.
  • The calendar grid. You know, each day in the current month, represented as a square in the grid.

Let’s write this up in a file called index.js. This can go inside a src folder in the project folder. We will indeed have an index.html file in the project root that imports our work, but the primary markup will live in the JavaScript file.

<!-- index.js -->
document.getElementById("app").innerHTML = `
<!-- Parent container for the calendar month -->
<div class="calendar-month">
  <!-- The calendar header -->
  <section class="calendar-month-header">
    <!-- Month name -->
    <div
      id="selected-month"
      class="calendar-month-header-selected-month"
    >
      July 2020
    </div>


    <!-- Pagination -->
    <div class="calendar-month-header-selectors">
      <span id="previous-month-selector"><</span>
      <span id="present-month-selector">Today</span>
      <span id="next-month-selector">></span>
    </div>
  </section>
  
  <!-- Calendar grid header -->
  <ol
    id="days-of-week"
    class="day-of-week"
  >
    <li>Mon</li>
    ...
    <li>Sun</li>
  </ol>


  <!-- Calendar grid -->
  <ol
    id="calendar-days"
    class="date-grid"
  >
    <li class="calendar-day">
      <span>
        1
      </span>
      ...
      <span>
        29
      </span>
    </li>
  </ol>
</div>
`;

Let’s go ahead and import this file into that index.html file that lives in the root directory of the project. Nothing special happening here. It’s merely HTML boilerplate with an element that’s targeted by our app and registers our index.js file.

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app"></div>

    <script src="src/index.js"></script>
  </body>
</html>

Now that we have some markup to work with, let’s style it up a bit so we have a good visual to start with. Specifically, we’re going to:

  • Position the elements using flexbox
  • Create a calendar frame using CSS grid
  • Position the labels within the cells

First up, let’s create a new styles.css file in the same src folder where we have index.js and drop this in:

body {
  --grey-100: #e4e9f0;
  --grey-200: #cfd7e3;
  --grey-300: #b5c0cd;
  --grey-800: #3e4e63;
  --grid-gap: 1px;
  --day-label-size: 20px;
}

.calendar-month {
  position: relative;
  /* Color of the day cell borders */
  background-color: var(--grey-200);
  border: solid 1px var(--grey-200);
}


/* Month indicator and selectors positioning */
.calendar-month-header {
  display: flex;
  justify-content: space-between;
  background-color: #fff;
  padding: 10px;
}


/* Month indicator */
.calendar-month-header-selected-month {
  font-size: 24px;
  font-weight: 600;
}


/* Month selectors positioning */
.calendar-month-header-selectors {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 80px;
}


.calendar-month-header-selectors > * {
  cursor: pointer;
}


/* | Mon | Tue | Wed | Thu | Fri | Sat | Sun | */
.day-of-week {
  color: var(--grey-800);
  font-size: 18px;
  background-color: #fff;
  padding-bottom: 5px;
  padding-top: 10px;
}


.day-of-week,
.days-grid {
  /* 7 equal columns for weekdays and days cells */
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}


.day-of-week > * {
  /* Position the weekday label within the cell */
  text-align: right;
  padding-right: 5px;
}


.days-grid {
  height: 100%;
  position: relative;
  /* Show border between the days */
  grid-column-gap: var(--grid-gap);
  grid-row-gap: var(--grid-gap);
  border-top: solid 1px var(--grey-200);
}


.calendar-day {
  position: relative;
  min-height: 100px;
  font-size: 16px;
  background-color: #fff;
  color: var(--grey-800);
  padding: 5px;
}


/* Position the day label within the day cell */
.calendar-day > span {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  right: 2px;
  width: var(--day-label-size);
  height: var(--day-label-size);
}

The key part that sets up our grid is this:

.day-of-week,
.days-grid {
  /* 7 equal columns for weekdays and days cells */
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

Notice that both the calendar grid header and the calendar grid itself are using CSS grid to lay things out. We know there will always be seven days in a week, so that allows us to use the repeat() function to create seven columns that are proportional to one another. We’re also declaring a min-height of 100px on each date of the calendar to make sure the rows are consistent.

We need to hook these styles up with the markup, so let’s add this to the top of our index.js file:

import "./styles.css";

This is a good spot to stop and see what we have so far.

Step 2: Setting up current month calendar

As you probably noticed, the template only contains static data at the moment. The month is hardcoded as July and the day numbers are hardcoded as well. That’s where Day.js comes into play. It provides all the data we need to properly place dates on the correct days of the week for a given month using real calendar data. It allows us to get and set anything from the start date of a month to all the date formatting options we need to display the data.

We will:

  • Get the current month
  • Calculate where the days should be placed (weekdays)
  • Calculate the days for displaying dates from the previous and next months
  • Put all of the days together in a single array

First, we need to import Day.js and remove all static HTML (selected month, weekdays and days). We’ll do that by adding this to our index.js file right above where we imported the styles:

import dayjs from "dayjs";

We’re also going to lean on a couple of Day.js plugins for help. WeekDay helps us set the first day of the week. Some prefer Sunday as the first day of the week. Other prefer Monday. Heck, in some cases, it makes sense to start with Friday. We’re going to start with Monday.

The weekOfYear plugin returns the numeric value for the current week out of all weeks in the year. There are 52 weeks in a year, so we’d say that the week starting January 1 is the the first week of the year, and so on.

So here what we put into index.js right after our import statements:

const weekday = require("dayjs/plugin/weekday");
const weekOfYear = require("dayjs/plugin/weekOfYear");


dayjs.extend(weekday);
dayjs.extend(weekOfYear);

Once we strip out the hardocded calendar values, Here’s what we have in index.js so far:

import dayjs from "dayjs";
import "./styles.css";
const weekday = require("dayjs/plugin/weekday");
const weekOfYear = require("dayjs/plugin/weekOfYear");


dayjs.extend(weekday);
dayjs.extend(weekOfYear);


document.getElementById("app").innerHTML = `
<div class="calendar-month">
  <section class="calendar-month-header">
    <div
      id="selected-month"
      class="calendar-month-header-selected-month"
    >
    </div>
    <div class="calendar-month-header-selectors">
      <span id="previous-month-selector"><</span>
      <span id="present-month-selector">Today</span>
      <span id="next-month-selector">></span>
    </div>
  </section>
  
  <ul
    id="days-of-week"
    class="day-of-week"
  >
  </ul>
  <ul
    id="calendar-days"
    class="days-grid"
  >
  </ul>
</div>
`;

Now let’s set few constants. Specifically, we want to construct an array of days of the weeks (i.e. Monday, Tuesday, Wednesday, etc.):

const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

Then, we want to fetch the current year and set in in YYYY format:

const INITIAL_YEAR = dayjs().format("YYYY");

And we want to set the current month as the starting point when initially loading the calendar, where M formats the month as a numeric value (e.g. January equals 1):

const INITIAL_MONTH = dayjs().format("M");

Let’s go and populate our calendar grid header with the days of the week. First we grab the proper element (#days-of-week), then we iterate through our WEEKDAYS array, creating a list item element for each item in the array while setting the name for each one:

// Select the calendar grid header element
const daysOfWeekElement = document.getElementById("days-of-week");


// Loop through the array of weekdays
WEEKDAYS.forEach(weekday => {
  // For each item in the array, make a list item element
  const weekDayElement = document.createElement("li");
  // Append a child element inside the list item...
  daysOfWeekElement.appendChild(weekDayElement);
  /// ...that contains the value in the array
  weekDayElement.innerText = weekday;
});

Step 3: Creating the calendar grid

That was pretty straightforward but now the real fun starts as we will now play with the calendar grid. Let’s stop for a second a think what we really need to do to get that right.

First, we want the date numbers to fall in the correct weekday columns. For example, July 1, 2020 is on a Wednesday. That’s where the date numbering should start.

If the first of the month falls on Wednesday, then that means we’ll have empty grid items for Monday and Tuesday in the first week. The last day of the month is July 31, which falls on a Friday. That means Saturday and Sunday will be empty in the last week of the grid. We went to fill those with the trailing and leading dates of the previous and next months, respectively, so that the calendar grid is always full.

Create days for the current month

To add the days for the current month to the grid, we need to know how many days exist in the current month. We can get that using the daysInMonth method provided by Day.js. Let’s create a helper method for that.

function getNumberOfDaysInMonth(year, month) {
  return dayjs(`${year}-${month}-01`).daysInMonth()
}

When we know that, we create an empty array with a length that’s equal to number of days in the current month. Then we map() that array and create a day object for each one. The object we create has an arbitrary structure, so you can add other properties if you need them.

In this example, though, we need a date property that will be used to check if a particular date is the current day. We’ll also return a dayOfMonth property that acts as the label (e.g. 1, 2, 3 and so on). isCurrentMonth checks whether the date is in the current month or outside of it. If it is outside the current month, we will style those so folks know they are outside the range of the current month.

function createDaysForCurrentMonth(year, month) {
  return [...Array(getNumberOfDaysInMonth(year, month))].map((day, index) => {
    return {
      date: dayjs(`${year}-${month}-${index + 1}`).format("YYYY-MM-DD"),
      dayOfMonth: index + 1,
      isCurrentMonth: true
    };
  });
}

Add dates from the previous month to the calendar grid

To get dates from the previous month to display in the current month, we need to check what is the weekday of the first day in selected month. That’s where we can use the WeekDay plugin for Day.js. Let’s create a helper method for that.

function getWeekday(date) {
  return dayjs(date).weekday()
}

Then, based on that, we need to check which day was the last Monday in the previous month. We need that value to know how many days from the previous month should be visible in the current month view. We can get that by subtracting the weekday value from the first day of the current month. For example, if first day of the month is Wednesday, we need to subtract 3 days to get last Monday of the previous month. Having that value allows us to create an array of day objects starting from the last Monday of the previous month through the end of that month.

function createDaysForPreviousMonth(year, month) {
  const firstDayOfTheMonthWeekday = getWeekday(currentMonthDays[0].date);


  const previousMonth = dayjs(`${year}-${month}-01`).subtract(1, "month");
  
  const previousMonthLastMondayDayOfMonth = dayjs(
    currentMonthDays[0].date
  ).subtract(firstDayOfTheMonthWeekday - 1, "day").date();


  // Account for first day of the month on  a Sunday (firstDayOfTheMonthWeekday === 0)
  const visibleNumberOfDaysFromPreviousMonth = firstDayOfTheMonthWeekday ? firstDayOfTheMonthWeekday - 1 : 6


  return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) => {    
    return {
      date: dayjs(
        `${previousMonth.year()}-${previousMonth.month() + 1}-${previousMonthLastMondayDayOfMonth + index}`
      ).format("YYYY-MM-DD"),
      dayOfMonth: previousMonthLastMondayDayOfMonth + index,
      isCurrentMonth: false
    };
  });
}

Add dates from the next month to the calendar grid

Now, let’s do the reverse and calculate which days we need from the next month to fill in the grid for the current month. Fortunately, we can use the same helper we just created for the previous month calculation. The difference is that we will calculate how many days from the next month should be visible by subtracting that weekday numeric value from 7.

So, for example, if the last day of the month is Saturday, we need to subtract 1 day from 7 to construct an array of dates needed from next month (Sunday).

function createDaysForNextMonth(year, month) {
  const lastDayOfTheMonthWeekday = getWeekday(`${year}-${month}-${currentMonthDays.length}`)


  const visibleNumberOfDaysFromNextMonth = lastDayOfTheMonthWeekday ? 7 - lastDayOfTheMonthWeekday : lastDayOfTheMonthWeekday


  return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {
    return {
      date: dayjs(`${year}-${Number(month) + 1}-${index + 1}`).format("YYYY-MM-DD"),
      dayOfMonth: index + 1,
      isCurrentMonth: false
    }
  })
}

OK, we know how to create all days we need, let’s use the methods we just created and then merge all days into a single array of all the days we want to show in the current month, including filler dates from the previous and next months.

let currentMonthDays = createDaysForCurrentMonth(INITIAL_YEAR, INITIAL_MONTH)
let previousMonthDays = createDaysForPreviousMonth(INITIAL_YEAR, INITIAL_MONTH, currentMonthDays[0])
let nextMonthDays = createDaysForNextMonth(INITIAL_YEAR, INITIAL_MONTH)


let days = [...this.previousMonthDays, ...this.currentMonthDays, ...this.nextMonthDays]

Here’s everything we just covered put together in index.js:

// Same as before ...


const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const INITIAL_YEAR = dayjs().format("YYYY");
const INITIAL_MONTH = dayjs().format("M");
const daysOfWeekElement = document.getElementById("days-of-week");


// Add weekdays to calendar header
WEEKDAYS.forEach(weekday => {
  const weekDayElement = document.createElement("li");
  daysOfWeekElement.appendChild(weekDayElement);
  weekDayElement.innerText = weekday;
});


let currentMonthDays = createDaysForCurrentMonth(INITIAL_YEAR, INITIAL_MONTH);
let previousMonthDays = createDaysForPreviousMonth(INITIAL_YEAR, INITIAL_MONTH);
let nextMonthDays = createDaysForNextMonth(INITIAL_YEAR, INITIAL_MONTH);
let days = [...previousMonthDays, ...currentMonthDays, ...nextMonthDays];


console.log(days);


function getNumberOfDaysInMonth(year, month) {
  return dayjs(`${year}-${month}-01`).daysInMonth();
}


function createDaysForCurrentMonth(year, month) {
  return [...Array(getNumberOfDaysInMonth(year, month))].map((day, index) => {
    return {
      date: dayjs(`${year}-${month}-${index + 1}`).format("YYYY-MM-DD"),
      dayOfMonth: index + 1,
      isCurrentMonth: true
    };
  });
}


function createDaysForPreviousMonth(year, month) {
  const firstDayOfTheMonthWeekday = getWeekday(currentMonthDays[0].date);
  const previousMonth = dayjs(`${year}-${month}-01`).subtract(1, "month");
  const previousMonthLastMondayDayOfMonth = dayjs(currentMonthDays[0].date)
    .subtract(firstDayOfTheMonthWeekday - 1, "day")
    .date();
  // Cover first day of the month being sunday (firstDayOfTheMonthWeekday === 0)
  const visibleNumberOfDaysFromPreviousMonth = firstDayOfTheMonthWeekday
    ? firstDayOfTheMonthWeekday - 1
    : 6;


  return [...Array(visibleNumberOfDaysFromPreviousMonth)].map((day, index) => {
    return {
      date: dayjs(
        `${previousMonth.year()}-${previousMonth.month() +
          1}-${previousMonthLastMondayDayOfMonth + index}`
      ).format("YYYY-MM-DD"),
      dayOfMonth: previousMonthLastMondayDayOfMonth + index,
      isCurrentMonth: false
    };
  });
}

function createDaysForNextMonth(year, month) {
  const lastDayOfTheMonthWeekday = getWeekday(
    `${year}-${month}-${currentMonthDays.length}`
  );
  const nextMonth = dayjs(`${year}-${month}-01`).add(1, "month");
  const visibleNumberOfDaysFromNextMonth = lastDayOfTheMonthWeekday
    ? 7 - lastDayOfTheMonthWeekday
    : lastDayOfTheMonthWeekday;
  return [...Array(visibleNumberOfDaysFromNextMonth)].map((day, index) => {
    return {
      date: dayjs(
        `${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`
      ).format("YYYY-MM-DD"),
      dayOfMonth: index + 1,
      isCurrentMonth: false
    };
  });
}

function getWeekday(date) {
  return dayjs(date).weekday();
}

Step 4: Show calendar dates

OK, so we have the basic markup for our calendar, the data we need to display dates from the current month, plus dates from the previous and next month to fill in empty grid items. Now we need to append the dates to the calendar!

We already have a container for the calendar grid, #calendar-days. Let’s grab that element.

const calendarDaysElement = document.getElementById("calendar-days");

Now, let’s create a function that will append a day to our calendar view.

function appendDay(day, calendarDaysElement) {
  const dayElement = document.createElement("li");
  const dayElementClassList = dayElement.classList;


  // Generic calendar day class
  dayElementClassList.add("calendar-day");


  // Container for day of month number
  const dayOfMonthElement = document.createElement("span");


  // Content
  dayOfMonthElement.innerText = day.dayOfMonth;


  // Add an extra class to differentiate current month days from prev/next month days
  if (!day.isCurrentMonth) {
    dayElementClassList.add("calendar-day--not-current");
  }


  // Append the element to the container element
  dayElement.appendChild(dayOfMonthElement);
  calendarDaysElement.appendChild(dayElement);
}

Notice that we’re tossing in a check for the dates that  are coming from the previous and next months so that we can add a class to style them differently from the dates in the current month:

.calendar-day--not-current {
  background-color: var(--grey-100);
  color: var(--grey-300);
}

That’s it! Our calendar should now look as we wanted.

Step 5: Select current month

What we have so far is pretty nice, but we want the user to be able to paginate from month-to-month forwards and backwards in time, starting from the current month. We have most of the logic in place, so all we really need to do is to add a click listener to the pagination buttons that re-runs the days calculation and re-draws the calendar with updated data.

Before we begin, let’s define variables for dates that are in the current month, previous month, and next month so we can reference them throughout the code.

let currentMonthDays;
let previousMonthDays;
let nextMonthDays;

Now, let’s create a method that will be responsible for re-calculating the calendar days and re-rendering the calendar when paginating to another month. We will call that function createCalendar. This method will accept two attributes — year and month  — and based on that, the calendar will re-render with new data and without a new page load.

The method will replace the header content to always show the selected month label.

function createCalendar(year = INITIAL_YEAR, month = INITIAL_MONTH) {
  document.getElementById("selected-month").innerText = dayjs(
    new Date(year, month - 1)
  ).format("MMMM YYYY");


  // ...

Then it will grab the calendar days container and remove all existing days.

// ...


  const calendarDaysElement = document.getElementById("calendar-days");
  removeAllDayElements(calendarDaysElement);


  // ...

When the calendar is cleared, it will calculate new days that should be displayed using the methods we created before.

//...


currentMonthDays = createDaysForCurrentMonth(
  year,
  month,
  dayjs(`${year}-${month}-01`).daysInMonth()
);


previousMonthDays = createDaysForPreviousMonth(year, month);


nextMonthDays = createDaysForNextMonth(year, month);


const days = [...previousMonthDays, ...currentMonthDays, ...nextMonthDays];


// ...

And, finally, it will append a day element for each day.

// ...
days.forEach(day => {
  appendDay(day, calendarDaysElement);
});

There is one piece of logic still missing: a removeAllDayElements method that clears the existing calendar. This method takes the first calendar day element, removes it, and replaces it with another one. From there, it will run the logic in a loop until all of the elements are removed.

function removeAllDayElements(calendarDaysElement) {
  let first = calendarDaysElement.firstElementChild;


  while (first) {
    first.remove();
    first = calendarDaysElement.firstElementChild;
  }
}

Now we can reuse that logic when we want to change the month. Recall the first step when we created a static template for our component. We added these elements:

<div class="calendar-month-header-selectors">
  <span id="previous-month-selector"><</span>
  <span id="present-month-selector">Today</span>
  <span id="next-month-selector">></span>
</div>

These are the controls for paginating between months. To change it, we need to store the currently selected month. Let’s create a variable to keep track of what that is and set its initial value to the present month.

let selectedMonth = dayjs(new Date(INITIAL_YEAR, INITIAL_MONTH - 1, 1));

Now, to make the selectors work, we need a bit of JavaScript. To make it more readable, we will create another method called initMonthSelectors and we will keep the logic there. This method will add event listeners to the selector elements. It will listen for click events and update the value of selectedMonth to the name of the newly selected month before running the createCalendar method with proper year and month values.

function initMonthSelectors() {
  document
  .getElementById("previous-month-selector")
  .addEventListener("click", function() {
    selectedMonth = dayjs(selectedMonth).subtract(1, "month");
    createCalendar(selectedMonth.format("YYYY"), selectedMonth.format("M"));
  });


  document
  .getElementById("present-month-selector")
  .addEventListener("click", function() {
    selectedMonth = dayjs(new Date(INITIAL_YEAR, INITIAL_MONTH - 1, 1));
    createCalendar(selectedMonth.format("YYYY"), selectedMonth.format("M"));
  });


  document
  .getElementById("next-month-selector")
  .addEventListener("click", function() {
    selectedMonth = dayjs(selectedMonth).add(1, "month");
    createCalendar(selectedMonth.format("YYYY"), selectedMonth.format("M"));
  });
}

That’s it! Our calendar is ready. While that’s great and all, it would be even nicer if we could mark the current date so it stands out from the rest. That shouldn’t be very hard. We are already styling days that are not in the selected month, so let’s do similar thing to that.

We’ll create a variable that’s set for today:

const TODAY = dayjs().format("YYYY-MM-DD");

Then, in the appendDay method where we apply a class for dates outside the current month, we have to add another check to see if the element is today’s date. If it is, we’ll add a class to that element:

function appendDay(day, calendarDaysElement) {
  // ...
  if (day.date === TODAY) {
    dayElementClassList.add("calendar-day--today");
  }
}

Now we can style it!

.calendar-day--today {
  padding-top: 4px;
}


.calendar-day--today > div {
  color: #fff;
  border-radius: 9999px;
  background-color: var(--grey-800);
}

Voilà, there we have it! Check out the final demo to see everything put together.


The post How to Make a Monthly Calendar With Real Data appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.