DEV Community

Cover image for Recreating Notion's Homepage with Tailwind CSS and Vue JS
Christian von Uffel
Christian von Uffel

Posted on • Updated on • Originally published at cvonu.com

Recreating Notion's Homepage with Tailwind CSS and Vue JS

View the Project:

My Recreation of Notion's Homepage

Compare it to the Original

Notion's Homepage

Deciding what to build to showoff my front-end skills

When I first decided to build something for the Digital Ocean Hackathon to show off my front-end webdev skills, I asked myself "What would be useful for a real business?"

The answer I came to is recreating the website of a real business, a business whose website is so important to them that it serves as a foundation of how they do business and serve their customers.

The first criteria I had was obvious to me: the business whose website I chose to recreate had to be huge, or at least hugely valuable.

The second criteria was less obvious: the business' website had to not depend on the use of outside assets and graphics to make it look nice. Pretty assets don't show off my front-end skills and don't show off how I can best help businesses.

So I wanted to recreate an existing successful business' website that uses a variety of CSS skills: flexbox, grid, and a variety of styles for images, text, and a lot of data that needed to be managed in a robust way.

After all, part of the reason I decided to recreate a serious internet business' homepage, is that I wanted to improve my front-end webdev process and this offered me the perfect challenge: totally doable, yet more complicated than any page I've created before.

I looked at a few sites before I chose one:

First I looked at Nike because I like their branding, but after looking at their website, I realized most of my work recreating it would just be copying their media assets.

Nike's Homepage

Sure, I could recreate their navigation menus using flexbox and product displays using grid, but most of my work wouldn't show through.

Second, I looked at Stripe. Stripe's website is beautiful, but boy is it complicated and, secondly, it has the same problem as Nike: recreating Stripe's website depends on using a lot of outside assets, except it's worse! Stripe's website uses assets that are harder to access and implement.

Stripe's Homepage

Still, Stripe's website uses some pretty cool layout designs I could recreate using grid. Maybe this is something I'll revisit later.

Lastly, I looked at Notion. Notion's website, like their application, is beautiful, friendly, and accessible. It uses a bunch of assets, but, unlike Stripe and Nike's websites, doesn't rely on them. It uses modern CSS skills like flexbox and grid and a lot of text data that's managed best dynamically using components.

Notion's homepage was the clear and obvious winner.

My Process

One thing I decided early on was that I wasn't going to look at the original webpage's code. If someone wants to hire me to create a website for them, I don't have any starting code to work with so I'm not going to use that here either. They'll simply hand me off some wireframes from Figma or Sketch with the assets I need and/or a validated product spec.

I recreated all the page's designs and layout by sight.

No inspecting code, no copying code. All translating what I see into what write.

For me, there's only one good solution for this "what you see is what you code" sort of webdev framework and that's Tailwind CSS

Tailwind is great because it removes the layer of abstraction and lock-in that makes global CSS so unmanageable.

Next, there's data. All the data serious internet business websites use is managed dynamically using components.

<!-- testimonials section -->
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-12 md:gap-16 p-8 md:p-16 mx-auto">
    <a href="#" v-for="testimonial in testimonials" class="bg-gray-100 rounded-lg border border-gray-100 hover:border-gray-300 p-4 flex flex-col items-start">
        <img :src="testimonial.companyLogo" :alt="testimonial.sourceTitle" class="h-12 object-contain object-left overflow-hidden">
        <div class="text-lg my-6 h-full">
            "{{testimonial.content.trim()}}"
        </div>
        <div class="text-sm flex">
            {{testimonial.source}}
        </div>
        <div class="text-sm text-gray-700 capitalize">
            {testimonial.sourceTitle}}
        </div>
    </a>
</div>
Enter fullscreen mode Exit fullscreen mode

You alter design and data using two separate processes which keep both safe from accidental changes to each other.

testimonials:[
    {
        companyLogo:"images/blinkist.png",
        content:"On notion, everything is in one place and everyone can find what they need on their own. We have cut down on interruptions, and stayed more focused on priorities.",
        source:"Milica Radojevic",
        sourceTitle:"People experience partner, Blinkist",
    },
    {
        companyLogo:"images/figma.png",
        content:"Notions ease-of-use is one of its hallmarks. It helps you visually navigate contact and remember where something is.",
        source:"Marie Szuts",
        sourceTitle:"Head of people ops, Figma",
    },
    {
        companyLogo:"images/duolingo.png",
        content:" we wouldn't be able to customize our workflow like this in any other product",
        source:"Justin Goff",
        sourceTitle:"product manager, duolingo",
    },
],
Enter fullscreen mode Exit fullscreen mode

Components let you update how data's displayed across your website without updating individual pages one by one.

Testimonials on Notion's Homepage

Avoiding code duplication helps you avoid making errors that make your website harder to manage, less friendly to use, and less focused on satisfying your users.

I manage the webpage's data using Vue JS. Its fast modern framework makes managing data easy and reliable.

But there's one problem with Vue JS and that's SEO.

Vue JS, like React and Angular, render a webpage's content dynamically, so they're not good for SEO.

To solve this problem, my next steps are rebuilding this site
using NUXT JS which builds static HTML pages to get all the benefits of dynamic rendering and component organization from Vue JS with all the SEO benefits of static HTML.

CSS Properties I Learned

pointer-events-none
Enter fullscreen mode Exit fullscreen mode

Makes images non-draggable

CSS Properties I knew, but hadn't used before

flex-row-reverse
Enter fullscreen mode Exit fullscreen mode

Useful for conditionally reversing the orientation of your footer elements on mobile, such as when you want to show a copyright notice on the left in your footer on desktop, but below everything else on mobile.

Top comments (0)