Reproduce Vercel's excellent dashboard page in using Tailwindcss and React components. This project could have easily been completed using vanilla HTML, however, given the reptitious nature of the Vercel dashboard React is used so that we can utilise components where there is repetition.

I feel I'm a competent Tailwind user, and before attempting this project I was a little hesitant as I wasn't sure how much value it would bring. I love Vercel's branding and user interface, but I love it because of its simplicity and minimalism not technical competance. However, I soon found the value in immersing yourself in a topic is exposing yourself to new techniques, and indeed just keeping on top of a skill-set, especially one as rapidly evolving as Tailwind.

The layout and design of the Vercel dashboard doesn't pose any obvious challenges (apart from popups, which have always given me an irrational fear 🤣). The key to sucess here is using Tailwind's utility classes to replicate the look and feel of the Vercel page as much as possible so as to produce no discernable differences, which I think we achieved at the end.

What did I learn?

The use of Tailwind's 'space-x' and 'space-y' directives instead of margins and padding

Tailwind's space-x and space-y directives were introduced in version 1.3. I've been using Tailwind since around version 1.0.1 and while I was familiar with their usage, I hadn't considered using them as Adam did in this tutorial.

Prior to this tutorial, when faced with a list of items that needed to be spaced correctly, or indeed one item, I would have used margins and/or padding.

<div>
    <h3>Section heading</h3>
    <ul>
        <li class="mt-2">Ut enim ad minim veniam</li>
        <li class="mt-2">Duis aute irure dolor in reprehenderit</li>
        <li class="mt-2">Lorem ipsum dolor sit amet</li>
    </ul>
</div>

There's a very puroseful use of margin-top here, and not margin-bottom. I was taught that you should always apply classes that affect the element it's applied to, not 'other' elements, be they previous or subsequent. It's much easier to understand your own layout and code this way, instead of trying to find which element is causing another element to be in the position its in.

Anyway, I digress. Let's have a look at the above code, this time using the space-y class.

<div>
    <h3>Section heading</h3>
    <ul class="space-y-2">
        <li>Ut enim ad minim veniam</li>
        <li>Duis aute irure dolor in reprehenderit</li>
        <li>Lorem ipsum dolor sit amet</li>
    </ul>
</div>

We can immediately see the above code is better in a number of ways. There's one declaration so no code repitition, and if we add aditional list elements we know they will automatically be spaced correctly. Although the ul tag controls how its children behave, not the children themselves, as long as we know this, this is not necassarily a negative thing given what I wrote about classes only affecting the element they're applied to.

New ways of passing props to a component in order to style it

As an aspiring developer, being able to style repeating components individually is certainly a boon. In this tutorial I learned the following technique.

function Avatar({ src, alt="", size="md" }) {

    const sizeClasses = ({
        sm: 'h-6 w-6',
        md: 'h-8 w-8',
    })[size]

    return (
        <img
            className={`${sizeClasses}w-8 h-8 border border-gray-200 rounded-full`}
            src={src}
            alt={alt}
        />
    )
}

<Avatar size="sm" src="..." alt="..."/>

This is far more efficient than techniques I have used in the past, such as passing in a page layout parameter to the component, and then using if statements inside the parameter to apply styles based on that parameter.

Quick and simple popups using React's useState

Having been building websites on and off since the early 2000's, popups and overlays have always filled me with fear. However in this project I loved the simple way of hiding and showing an overlay when a button is clicked.

function AccountSwitcher() {

    const [isOpen, setIsOpen] = useState(false)

    ...

    <button
        onClick={() => setIsOpen(!isOpen)}>
        ...
    </button>

    {isOpen && (
        <OverlayMarkup/>
        )
    }
}