No Time Dad

A blog about web development written by a busy dad

Responsive Card Header with Tailwind

Responsive design sometimes feels magical. Maybe intimidating is the right word? I’ve often found that I have more questions than answers when it comes to designing for different size screens. I’ve also found that I overthink it.

Lately, what I’ve come to realize that designing for the screen sizes that Chrome has as the defaults in the dev tools device toolbar is usually enough. Those widths (in pixels) are 328, 375, 425, 768, 1024, and 1440. And the truth is, I rarely design for any sizes between 328 and 768. I also rarely design for sizes between 768 and 1440.

So, when I look at it that way, I’m usually designing for two widths; 328px and 768px. That isn’t to say that I never design for in-between sizes, it’s just not nearly as common. That definitely makes responsive design less intimidating for me.

Another obvious thing that makes responsive design less intimidating is practice. Deliberate practice. Which brings me to the purpose of this blog post. Which is more practice.

In this post I’ll be creating a responsive card header with Tailwind. It’ll involve a lot of flexbox. I’ll start by designing for mobile device screens (328px wide) first, then move into larger screens (768px). Which is affectionately know as mobile first design.

You can jump down to the final code and demo for a sneak-peek at what the card header will look like.

Structuring the card

I’m going to use a box-shadow via Tailwind’s shadow utility class to define the outline of the card. The card is made up of a parent div with two child divs. One child div for the header and another for the content. The focus here will be on the header. Below is the initial html and example small screen element.

<div class="shadow-md rounded-md bg-white">
  <div>Header</div>
  <div>Content</div>
</div>
Header
Content

I can never make up my mind about where to put padding. In this example, I didn’t put padding in the parent div which would have added padding to the entire card. The reason I didn’t add it is because I want a horizontal line or bottom border going edge to edge of the card in the header. If the parent div already had padding then the horizontal line wouldn’t go edge to edge without negative values, and that feels wrong to me. The drawback to doing it this way is that I have to add padding to each individual part of the header, taking extra care to ensure it looks even. This is tedious and prone to error.

Building the header

This version of the card header should consist of two divs. One with an avatar, name, and job title. And another div with some action buttons. These two divs will stack on top of each other in a column on small screens, and switch to both being in a single row on larger screens.

I’ve gotten into the habit lately of designing layouts using boxes. It’s a little more work up front, but it helps me visualize the layout before I dive into the details of the elements in the box.

Smaller screens

The small screen parent div layout is not complex. In fact, it’s just two rows. The first row intializes a flexbox container via Tailwind’s flex utility class, and it centers the text with the avatar via items-center. The items-center utility class, which is equivalent to align-items: center;, has been very helpful for me when aligning things inside a flexbox container. I don’t have to think about it, it just works.

The name and job title sit inside of a div. I’m thinking of them as a single element even though it’s really two elements. I added a little bit of margin-left to this element via the ml-2 utility class to let the avatar and the text breathe a little.

Name
Job title
Email button phone button
Larger screens

On larger screens, all of the elements should be on a single row. I can use Tailwind’s md: prefix to establish the medium (768px) breakpoint on any utility classes.

The major change here will be that the header’s parent div will initialize a flexbox container which will force the two buttons divs onto a single row. Because the two divs are in a flexbox containers now, I can use margin-left: auto via Tailwind’s ml-auto utility class to push the button’s div to the right.

Name
Job title
Email button phone button

Below is how the html looks so far, still using the placeholder borders to help define the layout.

<div class="shadow-md rounded-md bg-white w-full">
  <div class="md:flex items-center">
    <div class="border border-red-500 flex items-center p-2">
      <div class="border rounded-full h-20 w-20 bg-gray-500"></div>
      <div class="md:ml-4 border border-purple-500">
        <div>Name</div>
        <div>Job title</div>
      </div>
    </div>
    <div class="flex md:flex-row md:ml-auto border border-green-500 p-2">Email button phone button</div>
  </div>
</div>
Fine-tuning inner elements

At this point I have a responsive structure for the card header and I can start fine-tuning and styling the inner elements of each section. A lot of the styling is my own personal taste, and me trying to keep accessibility and user experience in mind.

I’ll start by swapping out the avatar circle for an actual image from unsplash. I could’ve chosen a better sized image for this, but I didn’t want to spend a ton of time hunting for the perfect image. I used Tailwind’s h-20 and w-20 utility classes to the set the image width and height, and I also used rounded-full (an alias for border-radius: 9999px) to make the avatar a circle. Using border-radius: 9999px is new to me. I usually use border-radius: 100% to make circles, but I’m sure there is a good reason to not do it that way.

I can then update the name and job div. I like names to be prominant and bold, while the title can be less noticable. Less noticable usually means I’m reducing the opacity. Both of these are done via the font-bold and opacity-70 utility classes, respectively.

The last section is the div for the buttons. Buttons are such a headache sometimes. I wish they were easier to style and work with. Tailwind helps, but I still find them tedious. I grabbed a couple svg icons from heroicons for the buttons to jazz them up a bit. In order to have the text and svg icon line up, I initialized a flexbox container in the button element itself and used Tailwind’s items-center.

Conclusion

More responsive design practice in the bank. Another fun little project made a little easier with Tailwind. I’m starting to see a trend.

I think the buttons and their container were the most challenging part of this card header. Also, if I was using React or Vue I’d definitely want to create a button component. Re-creating buttons multiple times is not fun.

Final code & demo

Try resizing your browser window to see how the card changes on large and small screens.

<div class="shadow-md rounded-md bg-white w-full">
  <div class="md:flex md:items-center border-b">
    <div class="flex items-center p-4">
      <img class="h-20 w-20 rounded-full" src="./headshot_lady.jpg" alt="headshot" />
      <div class="ml-4">
        <div class="font-bold text-lg">Jenny Smith</div>
        <div class="opacity-70">CEO</div>
      </div>
    </div>
    <div class="md:ml-auto p-2 space-x-2 flex md:flex-row">
      <button class="p-2 border border-gray-300 rounded flex items-center hover:bg-gray-100 focus:ring-1 focus:ring-gray-300">
        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
          <path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
        </svg>
        Phone
      </button>
      <button class="p-2 border border-gray-300 rounded flex items-center hover:bg-gray-100 focus:ring-1 focus:ring-gray-300">
        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
          <path fill-rule="evenodd" d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z" clip-rule="evenodd" />
        </svg>
        Email
      </button>
    </div>
  </div>
  <div class="p-2 opacity-50">Content</div>
</div>
headshot
Jenny Smith
CEO
Content