Responsive components with grid and TailwindCSS
Tags: tailwindcss, grid, flexbox, css
Published: 2023-02-15 13:36:24

---
title: Responsive components with grid and TailwindCSS
published: true
description: Develop responsive components by changing structure with grid and TailwindCSS
tags: tailwindcss,grid,flexbox,css
cover_image: https://images.unsplash.com/photo-1518893714388-8ed554f8471b?fit=crop&w=1000&h=420
canonical_url: https://sdorra.dev/posts/2023-02-10-responsive-components-with-grid
---

If we want to build real responsive components, it is often no longer enough to let something slide into the next line. Sometimes it is necessary to change the structure of a component and this can quickly become complicated. I would like to use the following example to show how the problem can be solved with Flexbox and Grid.

## The Example

Let's assume that we want to implement the following card:

![Card with avatar, title and description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avj7rezejlaxmj93v88v.png)

The card consists of an avatar, a title and a short description text.
In the mobile view the avatar and the title should be in the same line and the description should take up the whole line below.

For larger viewports, we want the avatar to be larger and the description to be next to the avatar as well.

![Card with avatar, title and description for larger viewports](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ak4h1wmwxysym3bo2o7s.png)

Ok, let's see how we can implement this.

## Flex solution

We start with a flexbox implementation, because I always start with flexbox.
An initial implementation of the mobile variant could look like this:

```tsx
<section>
  <div className="flex items-center gap-4">
    <Avatar className="h-16 w-16" />
    <h3 className="text-2xl font-bold">Title</h3>
  </div>
  <p className="mt-5">Description</p>
</section>
```

But when we try to implement the larger viewports, it gets difficult quickly.
The problem is that the structure changes.
The only solution I can think of here is to duplicate the description:

```tsx
<section>
  <div className="flex items-center gap-4">
    <Avatar className="h-16 w-16 flex-shrink-0 sm:h-24 sm:w-24" />
    <div className="w-full">
      <h3 className="text-2xl font-bold">Title</h3>
      <p className="mt-5 hidden sm:block">Description</p>
    </div>
  </div>
  <p className="mt-5 sm:hidden">Description</p>
</section>
```

To solve the problem we had to group the title and description with a `div`,
hide the description (`hidden`) and
only show it when we are in a larger viewport (`sm:block`).
The description for the small viewport is displayed by default and
is hidden when we are in a larger viewport (`sm:hidden`).

But we need to do more.
The grouping of the title can cause the avatar to be squeezed,
so we need to add a `w-full` to the grouping `div` and a `flex-shrink-0` to the avatar.

This solution is far from optimal.
We had to include more markup and we had to duplicate content.
There is probably a better way to solve this problem with Flexbox,
but I couldn't think of one.

**If you know of a better solution, please leave a comment**

## Grid to the rescue

Lets try to implement the same layout with grid instead of flexbox.
We start again with the mobile view:

```tsx
<section className="grid grid-cols-[5rem,1fr] items-center">
  <Avatar className="h-16 w-16" />
  <h3 className="text-2xl font-bold">Title</h3>
  <p className="col-span-2 mt-5">Description</p>
</section>
```

Except for the arbitrary value for grid-cols, the whole thing is pretty simple.
We create a grid with 2 columns, the first is 5rem wide (1rem wider than the avatar) and the second is 1fr wide (`grid grid-cols-[5rem,1fr]`).
In the first column of the first row is the avatar,
in the second column is the title.
We have extended the description to two columns (`col-span-2`) and
it is in the second row.

![Grid for mobile viewport](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xruasgwxbqv0u56kc8t3.png)

In the case of the larger viewport,
we actually only need to draw the avatar over 2 lines and
take back the col span of the description.

![Grid for larger viewports](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/092x894qr9r1cg196nkd.png)

The whole thing could look like this:

```tsx
<section className="grid grid-cols-[5rem,1fr] items-center sm:grid-cols-[7rem,1fr]">
  <Avatar className="row-span-2 h-16 w-16 sm:h-24 sm:w-24" />
  <h3 className="text-2xl font-bold">Title</h3>
  <p className="col-span-2 mt-5 sm:col-span-1">Description</p>
</section>
```

With the `row-span-2` we could draw the avatar over both lines and
with `sm:col-span-1` we reset the col span of the description.
We also had to reserve more space for the avatar in the first column of the grid (`sm:grid-cols-[7rem,1fr]`).

## Conclusion

With the grid solution we needed much less markup.
We also didn't need duplication anymore and it's also much easier to understand.