How to replicate the Zelda BOTW interface with React, Tailwind and Framer-motion: Part 2
Tags: react, tailwind, framermotion
Published: 2020-07-05 07:54:20

---
series: zeldabotwgameui
---

# Introduction and notes on first part

Welcome back for the second part of the **Zelda series**.
I hope that you manage to complete the first part without much trouble. If not or if you've missed the first part I created a [checkpoint](https://github.com/Flow11/zelda-botw-starter/tree/part1-checkpoint) branch with all the steps completed.
Also there were some errors in the solutions provided in part 1 that should all be fixed now.

After the first part, our interface should looks like this:

![Checkpoint part1](https://dev-to-uploads.s3.amazonaws.com/i/vhx147hl0hgd19zogfke.png)

In this second part we'll focus first on the **right column** of our layout and then we're going to handle **items pagination** and ways to navigate between them.

For providing solutions I decided to stop using _gist files_, they were hard to maintain and even for reading it was not convenient either to jump between files for the same solution.
Instead I created a checkpoint commit at each step of the second part, it should make reading easier hopefully.


# Displaying additional items information

## Right column layout

We're going to start by creating the base blocks of the right column.

![Layout](https://dev-to-uploads.s3.amazonaws.com/i/bsqw7o3zxj32gvqhkcll.png)

We need an **ItemInformation** component that should be displayed at the bottom of the column. For now the component should be an empty box, but its width should match the **ItemGrid** width when we are in column display.

Once the **ItemInformation** component is set, we'll need to position the _Link_ image below and hide it for breakpoints below XL. We can use an _absolute_ here for the positioning.



### Notes

The color for the **ItemInformation** background is missing  in the starter tailwind configuration file. We can add it now:

`bgBlackTransparent: "rgba(0, 0, 0, 0.5)",`

### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/b99de506b9572e66570f0bfe04f1c3f9cdef7963)

## Items information

Now we're going to display more Item information. This step is mostly passing down props and implementing the design of the ItemInformation component.

![Item information](https://dev-to-uploads.s3.amazonaws.com/i/3334aa50qa0kadec7q51.png)


We want to display the _name_, _value_, _category_ and _description_ of the item. The category will be displayed as an Icon. In the first part we've displayed only one category among the 3 available in the dataset but we'll handle all 3 cases here. We need to create a **CategoryIcon** component which displays the appropriate icon based on a _type_ props for example.

But first we have to convert our SVGs (_Armor_, _Shield_, _Sword_) inside _src/assets/items_ into React components. We will use [SVGR](https://react-svgr.com/playground/) for that.

On this step we will also add the calamity font since this is the first time we will display text. It is available in the font folder under _assets_. We have to move it to _create-react-app_ public folder and add _font-face_ declarations in a separate _css_ file.

### Notes

We can reuse the _Armor_ icon for _helm_ and _greave_ category.

### Ressources

- https://developer.mozilla.org/fr/docs/Web/CSS/@font-face

### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/39a8eacbe109368fcbb159c4c00aa247290fbf18)


## Adding a component to animate text

Now we are going to animate the item description by adding a typewriter effect animation.

![Windups](https://dev-to-uploads.s3.amazonaws.com/i/qexun5t910tzjtred1z7.png)

To achieve this effect we are going to use the [windups](https://windups.gwil.co/) library from [@sgwil](https://twitter.com/sgwil). The library is really well written, has a nice API and great documentation. We can even trigger effects, like sounds, during the animation. For this demo we are just going to use the base functionality of _windups_ with the _useWindupString_ hook provided for React.
This hook renders a lot of time so we should avoid using it at a high level in our app structure otherwise it would trigger a lot of unneeded render on children components and seriously lower the performance of our interface.
Instead we will create a **TypeWriter** component that we will use inside **ItemInformation**.

### Notes

Have a look at the [interactive guides](https://windups.gwil.co/quick) to get a feeling of what you can do with _windups_ or even the [sources](https://github.com/sgwilym/windups) if you have some time they are really interesting.

### Ressources

- [useWindupString doc](https://windups.gwil.co/api#use-windup-string)


### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/c3bc905c270f3cde92035661084f5cf0bc804969)


# Adding pagination 


## Handling pagination logic

In the first part we create a _getItems_ function to retrieve one category of items and fill the rest of the grid cells with an empty item object.

Now we have to tweak this function a bit to return all the categories of items by page.

The function should have the following **ItemsPage** return type

```ts

export enum ItemsMainCategoriesType {
  WEAPONS = "weapons",
  SHIELDS = "shields",
  ARMORS = "armors",
}

export type ItemsPage = {
  items: ItemType[];
  mainCategory: ItemsMainCategoriesType;
  page: number;
};

```

Once that is done we need to create two states using _useState_ react hook inside our **App** component:
- One that should be initialized with the result of our _getItems_ function
- Another one to store the current page, that we initialize to 0 for now
- Then we need to create our new _items_ variable based on the active page


At the end of this step we won't be able to navigate between pages yet but we'll have the base logic ready.


### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/f0b60bfa47e99b365518a0479ef4b691433174bf)


## Creating a component for page navigation

For the next part we're going to create the component to move between the groups of items, we can call it **CategoriesMenu**. We'll also need a component for each item inside that menu, we can call it **CategoriesMenuItem**.

![Categories menu](https://dev-to-uploads.s3.amazonaws.com/i/addzdxwrssxybbgtwhbm.png)

The **CategoriesMenuItem** will have to display one of the 3 SVG react components (Weapon, Shield, Armor) and call the _setPage_ from earlier on click. In the image, the first icon is selected and has different style applied.


### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/054043d51181f0f45ac59f65be21d4100920aabd)


## Adding animated arrow to navigate

We are now going to provide a second way to navigate between the pages with arrows at the edge of the items grid component.

![Navigation arrows](https://dev-to-uploads.s3.amazonaws.com/i/9fla22n6g0io1r5jqr4d.png)

This time instead of calling _setPage_ directly, we'll create a _navigateToDirection_ function which should either take _1_ or _-1_ to represent the direction and then call _setPage_ with the appropriate value.

These arrows should:
- call _navigateToDirection_
- be animated on the _scale_ property to create a zoom in/out effect with framer motion
- be disabled if reaching either max/min page.


We'll also have to update our _useState_ inside **App** to store both the page and the direction.

### Notes

The arrow image is available under the asset folder under the name _arrow-no-curve.png_. We may have to move it to the public folder to use a static url directly.

We only have one arrow as an image, so we need to rotate the image to create the left arrow.


### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/c0a148ce30be26b0ab2c545cb6fe437d262152d9)


## Handling keyboard to navigate between page

We are now going to provide a third way to navigate between the pages ! **Triforce requirement**, we have no choice. 

![Keyboard navigation](https://dev-to-uploads.s3.amazonaws.com/i/p952m4w4j02diytiaykv.png)

For this step we have to change the _handleKeyPressed_ and _goLeft_ / _goRight_ functions we wrote in part 1.
- _handleKeyPressed_: we need to call _navigateToDirection_ inside **ArrowLeft** and **ArrowRight** event when we are at the edges of the **ItemsGrid**
- _goLeft_ / _goRight_: we loop over horizontal cells when we reach the edges of the ItemGrid.

### Notes

We can optionally refactor the _if/else_ inside the _handleKeyPressed_ function by a _switch block_.


### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/d55e06c03f86477e431c84dc644b53442ad349b4)


## Adding animation on page change

For the last part we are going to add an animation to the page transition.

![Page animation](https://dev-to-uploads.s3.amazonaws.com/i/v4u30c7jc5bx8tmgimim.png)

The animation will be added to the **ItemsGrid** component. We want to slide the ItemsGrid from the right or from the left depending on the _direction_ that we stored in our _useState_.
To create this animation we are going to use the _variant_ api from _framer-motion_, it allows us to define the different states of our animation in an object. In this object we will have two states:
- _enter_: this is the starting position, here we will slide the ItemsGrid to either _-100_ or _100_ on the _x_ axis and apply an opacity to 0.
- _center_: here we will move the **ItemsGrid** back to the center and reveal the **ItemsGrid** at the same time with _opacity_ to 1.

To sum up we are going to give our _motion.div_ a _variant_ object with two entries _enter_ and _center_. Each entry will define values for _x_ and _opacity_ properties. It should look like this:

```ts
const variants = {
  enter: (direction: number) => {
    return {
      x: ??,
      opacity: ??,
    };
  },
  center: {
    x: ??,
    opacity: ??,
  },
};
```


We'll also need to define the transition we want for these properties, we can use the values below:

```tsx
      transition={{
        x: { type: "tween" },
        opacity: { duration: 0.2 },
      }}
```

In the end our _motion.div_ component inside **ItemsGrid** should have the following props:

```jsx
<motion.div
    custom={direction}
    variants={variants}
    initial="enter"
    animate="center"
    transition={{...}}
/>
```

Since there is no direction involved when we change pages using the **CategoriesMenu** we should probably just animate the opacity in this case.

### Ressources

- [Variant API](https://www.framer.com/api/motion/animation/#variants) 

### Solution

- [Checkpoint commit](https://github.com/Flow11/zelda-botw-starter/commit/993426d6a11b54c32d18e99c46c4e1daf1b53173)


# What's next

Congratulations for completing part 2 we've made a lot of progress on completing our demo.
In part 3 we will add the final touch to bring this interface to life !
Again feel free to share any feedback and I hope you had fun.