No Time Dad

A blog about web development written by a busy dad

Recreating TailwindUI's Call to Action Component in Plain CSS

Intro

A fun exercise I’ve been doing lately to improve my CSS skills is to take some of the components from TailwindUI and try to reproduce them using only CSS, no libraries. This has mostly gone ok. It has definitely helped me increase my CSS knowledge and has shown me just how good these TailwindUI components really are. I’d say that I can get them to about 80% of what the actual Tailwind implementation is.

I’ve felt for a while that CSS skills were really lacking and I was little embarassed by that fact. A week or so ago I started tinkering with Tailwindcss and that only made it more clear just how much CSS knowledge I was lacking. So, I decided to go back to the basics and just try to get a better understanding of CSS concepts in general.

Generally speaking, I learn better by doing so I figured a good place to start would be to just start making things. The TailwindUI components are super high quality, so I figured that was probably a good place to start.

Lessons So Far

  • Writing CSS from scratch is tedious, but it is also fun. I have been using web frameworks for so long that it actually felt pretty good to be in control of everything for once. The downside to this is that I am control of everything and I quickly realized just how much these web frameworks were doing for me. I am currently undecided on how I feel about this.

  • Inspecting elements feels a little bit like cheating. For “learning purposes” I have been trying hard to just “figure it out”, but sometimes I just have to inspect element and see how something is done. This is especially true with TailwindUI components because they can be really complex. Once I have a general idea of how something should be laid out I’ll inspect element to get the exact spacing, but other than that I have been trying to make my own decisions based on research or guessing.

  • Once I feel comfortable enough with CSS I am absolutely going to use Tailwindcss. I am getting really tired of naming classes, especially now that I have gotten a taste for utility classes.

  • Emmet is a lifesaver, and I cannot believe I didn’t know about this sooner. It saves so much time. I like it so much I might do a dedicated write-up on Emmet at some point. Here is an awesome video explaining Emmet shortcuts in VSCode.

CTA Component

Here is the example TailwindUI component I was working on recreating. It is responsive and does a few neat things when you resize; including changing the display and resizing the text. This was my first attempt at writing media breakpoints and it went mostly ok. I am still a little unclear on when I should use max-width or min-width, so I need to do a little more research on that.

Another fun discovery was that Tailwindcss removes padding the h1 tags, which took me a little while to realizes so I had an interesting spacing battle going on for a while. I also enjoyed figuring out the purple text span inside the h1 and getting the display correct for that text. I would have never thought to add an inner span like that.

The button shadow was super annoying. I need to spend some more time trying to understand box-shadow because it is still sort of mysterious to me. I am sort of bummed about it, but I ended up just copying the Tailwindss class .shadow for this.

Anyways, like I said at the start, it is not an exact replica but it is pretty close. It was fun and I’ll keep trying to recreate things in plain css for a while until I feel good about my skills.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="./styles.css">
  <title>Document</title>
</head>
<body>
  <main>
    <div class="text-container">
      <h1>Ready to dive in? <span class="lower-text">Start your free trial today.</span></h1>
    </div>
    <div class="link-container">
      <div><a class="link-button get-started-button shadow" href="#">Get Started</a></div>
      <div><a class="link-button learn-more-button shadow" href="#">Learn More</a></div>
    </div>
  </main>
</body>
</html>
body {
  padding: 0;
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
}

h1 {
  padding: 0;
  margin: 0;
  word-spacing: -2px;
}

main {
  padding-left: 1rem;
  padding-right: 1rem;
  padding-top: 3rem;
  padding-bottom: 3rem;
  background-color: rgba(249, 250, 251, 1);
}

.lower-text {
  display: block;
  color: rgba(79, 70, 229, 1)
}

.bg-gray-50 {
  --tw-bg-opacity: 1;
  background-color: rgba(249, 250, 251, var(--tw-bg-opacity));
}

.text-container {
  display: flex;
}

.link-container {
  padding-top: 3rem;
  padding-bottom: 3rem;
  display: flex;
}

.link-button {
  text-decoration: none;
  padding: .75rem 1rem;
  border-radius: .5rem;
  font-weight: bolder;
}

.get-started-button {
  background-color: rgba(79, 70, 229, 1);
  color: white;
}

.get-started-button:hover {
  background-color: rgba(67, 56, 202, 1);
}

.learn-more-button {
  margin-left: 1rem;
  background-color: white;
  color: rgba(79, 70, 229, 1);
}

.learn-more-button:hover {
  background-color: rgba(238, 242, 255, 1);
}

.shadow {
  --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

@media only screen and (min-width: 800px) {
  main {
    display: flex;
    align-items: center;
  }

  .link-container {
    margin-left: auto;
  }
}

@media only screen and (min-width: 600px) {
  .text-container {
    font-size: 18px;
  }
}