Oct 09, 2020

A PWA Pokédex built with Gatsby

Check out the app here! The desktop design is still in the works, so view on mobile for the best experience. I focused on mobile-first design using Framer Motion to enhance user experience with custom animations and persistent layouts when navigating between pages.


I've been a Pokémon fan since I was a little kid. My siblings and I used to wake up every Saturday morning to watch the show, we'd check out the books from the public library, and we'd play Yellow and Red on our GameBoy Colors. Fast forward to 2020, I've grown frustrated with the quality of various Pokédex-like sites and apps. Sites like Serebii have high quality information, but the UX/UI is terrible. Others that have a better interface are often pretty slow. So I decided that I would make my own!

I had recently made a GraphQL Pokémon API, so I decided to make a frontend application for it. I went with Gatsby because since all of the data I want is static, I could make all of the pages at build time and not have to worry about having to host my GraphQL server anywhere. Then the app would be nice and fast in production since you wouldn't have to wait for any API calls to come back with the data and populate the pages. They're already pre-built! I also decided to have the site be a Progressive Web App so that you can download the site onto your phone like an app and access it more easily. Someday I'll learn React Native, but for now a PWA it is 😊

**Disclaimers: The amount and accuracy of the data is also reliant on PokéAPI. Any inaccuracies can be filed as issues on their GitHub repo.

This was never meant to be a site to the same caliber as Serebii. It's "just" a Pokédex with data about the Pokémon, not news about shows or games or anything.

I did, however, include a "News" page that pulls in tweets from various Pokémon Twitter accounts, like the official accounts and Serebii. So you can still get some news updates that way.


Like with any project, there were some challenging problems I had to figure out.

Framer Motion and Gatsby

I really wanted this app to be nice and slick. I wanted the animations to provide a smooth user experience that seem as native as possible without actually being a native app. I've worked with Framer Motion on previous projects, but never this in-depth or with Gatsby. This proved to be a significant challenge with some of the layout animations. Learning more in detail how Framer Motion works helped me then be able to figure out a solution for Gatsby that required wrapping my pages in a shared layout so that they could all be wrapped in the AnimateSharedLayout Framer Motion component I needed, without it mounting/unmounting on every page navigation. Now with Gatsby playing nicely with Framer Motion, there's a smoother experience when navigating from the home page to a Pokémon's page.

Demo of card expansion page transition from Pokémon home page to details page

Evolution Logic

One surprising challenge was figuring out the logic for the Pokémon evolution lines. The way that the PokéAPI database was set up, you could access what a Pokémon evolved from, but not what they evolved to. For the API, it was easy enough to write the SQL query to get that info. But how do you get the entire evolution line just from that info? Sounds easy enough, just do a loop until you find a Pokémon in the sequence that can't evolve anymore, right? It actually turned out to be a challenge because some Pokémon have multiple options for what they can evolve into. And there are different "criteria" that need to be met that determine which evolution form they take. And then how do you dynamically get a Pokémon's evolution line when you could be "starting" at a different evolution level? For example, when I open Ralts' page, he's the first Pokémon in his line. It needs to then calculate who all of his possible evolution options are. But what if I started at Gallade, one of Ralts' third level evolutions? He still has the same evolution line as Ralts, but we need to find who he evolves from, too. I landed on a recursive solution so that I could keep checking if the Pokémon can keep evolving to or from something else. I think it turned out pretty well!

Demo of Ralt's evolution line showing the toggle to look at either Gallade or Gardevoir

Loading Lag

An issue I'm currently working on is the loading lag on the Pokémon home page. There are so many Pokémon on the page, each with their own image that needs to get loaded, that all of those components on the page feel a bit choppy as you scroll. As a result, I only included the first generation of Pokémon in the deployed app until I can optimize it. After looking into options like lazy loading and react-window, I opted for a custom virtualization component to have better control over styling. It's been a fun challenge figuring out an algorithm to dynamically calculate when which components can be rendered and which ones can be unmounted. It's not pushed to production yet, as I want to make sure I have the kinks all worked out, but I'm really excited about it!


I'm pretty proud of how this app is coming along! While it's still pretty basic MVP, I've enjoyed the challenges that I've overcome and the satisfaction that comes with solving a problem. I've gotten better at recursion from working through the evolution logic. I think this is the first project I've done where I've actually implemented a working recursive solution. While I still have a lot of room for improvement, I'm excited for the progress I've made.

I love that there's a much shorter waiting time for opening a Pokémon's page of data when compared to other Pokédex apps simply because there's no wait time for an API request. All of that was done at build time, so Gatsby just has to deliver the pre-built HTML.