Borders, Rings & Shadows

Tailwind CSS · Lesson 9 of 27 7 min read Updated

Borders, rounded corners and shadows turn flat boxes into cards, buttons and panels that feel separate from the page. Rings and outlines show which element has keyboard focus. Tailwind has a utility for each, and they combine freely.

In this lesson you will draw borders on any side, round corners, separate list items with dividers, lift elements with shadows, and draw focus rings that do not move your layout. You will also learn the defaults that changed between Tailwind v3 and v4, because they explain many "why does my border look black?" questions.

Borders

border adds a 1px solid border on all sides. Add a number for thicker borders and a side for one edge only:

ClassResult
border1px on all sides
border-2, border-4, border-82px, 4px, 8px on all sides
border-t, border-b-2Top only, bottom only (2px)
border-x, border-yLeft and right, top and bottom
border-s-4, border-eInline start and end, which flip in right-to-left pages
border-0No border

Change the style with border-dashed, border-dotted or border-double, and the colour with any palette colour: border-slate-200, border-sky-500, border-red-500/50.

Rounded corners

rounded-* sets border-radius from a named scale:

ClassRadius
rounded-xs0.125rem (2px)
rounded-sm0.25rem (4px)
rounded-md0.375rem (6px)
rounded-lg0.5rem (8px)
rounded-xl0.75rem (12px)
rounded-2xl1rem (16px)
rounded-3xl, rounded-4xl1.5rem, 2rem
rounded-fullA pill, or a circle on a square element

Round only some corners with a side or corner: rounded-t-xl rounds the top two corners, rounded-s-lg the two start corners, and rounded-br-2xl just the bottom-right one.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Borders and radius</title>
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3"></script>
</head>
<body class="flex flex-wrap gap-4 p-6 text-sm">
  <div class="rounded-lg border border-slate-300 p-4">border rounded-lg</div>
  <div class="rounded-xl border-2 border-dashed border-sky-500 p-4">border-2 dashed</div>
  <div class="border-s-4 border-amber-500 bg-amber-50 p-4">border-s-4 (callout)</div>
  <div class="rounded-t-2xl border-b-4 border-emerald-600 bg-emerald-50 p-4">rounded-t-2xl border-b-4</div>
  <div class="rounded-full bg-slate-900 px-5 py-2 text-white">rounded-full pill</div>
  <img src="https://course.ethicscomputer.in/assets/samples/avatar.svg" alt="Isha" class="size-14 rounded-full border-4 border-white ring-2 ring-sky-500">
</body>
</html>

Dividers between items

For a list of rows, putting border-b on each item leaves an extra line under the last one. The divide-* utilities go on the parent and add a border between children only:

HTML
<ul class="divide-y divide-slate-200 rounded-xl border border-slate-200">
  <li class="p-3">Aarav: 92</li>
  <li class="p-3">Priya: 88</li>
  <li class="p-3">Rohan: 85</li>
</ul>

divide-y draws horizontal lines between rows and divide-x draws vertical lines between columns; divide-slate-200 colours them.

Shadows

shadow-* adds a box shadow from a scale that goes from barely visible to dramatic: shadow-2xs, shadow-xs, shadow-sm, shadow-md, shadow-lg, shadow-xl and shadow-2xl. Remove a shadow with shadow-none.

Shadows can be coloured too: shadow-lg shadow-sky-500/30 gives a soft blue glow under a blue button. Two other kinds are useful:

  • inset-shadow-* draws the shadow inside the element, which makes it look pressed in, like an input field.
  • drop-shadow-* is a CSS filter. Unlike a box shadow, it follows the actual shape of transparent images and SVG icons instead of their rectangular box.
HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Shadows</title>
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3"></script>
</head>
<body class="bg-slate-100 p-8">
  <div class="grid max-w-3xl gap-6 text-sm sm:grid-cols-4">
    <div class="rounded-xl bg-white p-4 shadow-xs">shadow-xs</div>
    <div class="rounded-xl bg-white p-4 shadow-md">shadow-md</div>
    <div class="rounded-xl bg-white p-4 shadow-xl">shadow-xl</div>
    <div class="rounded-xl bg-white p-4 shadow-2xl">shadow-2xl</div>
    <button class="rounded-xl bg-sky-600 p-4 text-white shadow-lg shadow-sky-600/40">coloured shadow</button>
    <div class="rounded-xl bg-slate-50 p-4 inset-shadow-sm">inset-shadow-sm</div>
    <svg viewBox="0 0 24 24" class="size-16 fill-amber-400 drop-shadow-xl" aria-hidden="true"><path d="M12 2l3 7h7l-5.5 4.5 2 7.5-6.5-4.5-6.5 4.5 2-7.5L2 9h7z"/></svg>
    <svg viewBox="0 0 24 24" class="size-16 fill-amber-400 shadow-xl" aria-hidden="true"><path d="M12 2l3 7h7l-5.5 4.5 2 7.5-6.5-4.5-6.5 4.5 2-7.5L2 9h7z"/></svg>
  </div>
</body>
</html>

Compare the two stars: drop-shadow-xl follows the star's points, while shadow-xl draws a shadow around the invisible square box of the SVG.

Rings and outlines

A ring is a solid line drawn around an element using a box shadow. Because shadows take up no space, a ring never moves other elements, which makes it perfect for selected states and focus indicators.

  • ring draws a 1px ring; ring-2, ring-4 are thicker. ring-sky-500 colours it.
  • ring-offset-2 adds a 2px gap between the element and the ring; ring-offset-white colours that gap.
  • inset-ring-* draws the ring inside the element instead.

An outline is the CSS property browsers use for focus by default: outline-2 outline-offset-2 outline-sky-600. Both are usually applied only on focus, using the focus-visible: variant you will meet in Hover, Focus & Other States. Press Tab in this example to move between the buttons:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Rings and outlines</title>
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3"></script>
</head>
<body class="flex flex-wrap gap-4 p-8">
  <button class="rounded-lg bg-sky-600 px-4 py-2 text-white focus-visible:ring-4 focus-visible:ring-sky-300 focus-visible:outline-none">Ring on focus</button>
  <button class="rounded-lg bg-emerald-600 px-4 py-2 text-white focus-visible:ring-2 focus-visible:ring-emerald-600 focus-visible:ring-offset-2 focus-visible:outline-none">Ring with offset</button>
  <button class="rounded-lg bg-slate-800 px-4 py-2 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-800">Outline on focus</button>
  <div class="rounded-lg bg-white px-4 py-2 ring-2 ring-amber-400">Always-on ring (selected plan)</div>
</body>
</html>

Common mistakes

  • Borders with no colour. They take the text colour in v4. Add border-slate-200 or similar.
  • Removing focus styles. Never use outline-none without adding a visible focus-visible: ring or outline in its place; keyboard users need to see where they are.
  • Borders that shift the layout. Adding border-2 on hover makes the element 4px bigger and nudges its neighbours. Use a ring, or keep a transparent border all the time and only change its colour.
  • Heavy shadows everywhere. Use small shadows for cards and save shadow-xl and shadow-2xl for floating things like menus and dialogs.

Key points

  • border, border-2 and side classes like border-b-4 set width; always add a colour such as border-slate-200.
  • rounded-* uses a scale from rounded-xs to rounded-4xl, plus rounded-full for pills and circles.
  • divide-y and divide-x on a parent draw lines between children only.
  • shadow-* lifts elements; add a colour like shadow-sky-500/30, or use inset-shadow-* and drop-shadow-* for other effects.
  • Rings (ring-2 ring-offset-2) and outlines are ideal for focus indicators because they do not change the layout.

Exercise

Build a pricing card for a coaching centre in Jaipur. The card should have a light border, rounded-2xl corners and a medium shadow. Inside, list three features separated by dividers. Mark the card as the "Most popular" plan with a 2px sky-coloured ring and a 4px offset, and give the "Join now" button a visible ring when it receives keyboard focus.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Pricing card</title>
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3"></script>
</head>
<body class="bg-slate-50 p-10">
  <article class="max-w-xs rounded-2xl border border-slate-200 bg-white p-6 shadow-md ring-2 ring-sky-500 ring-offset-4">
    <p class="text-sm font-semibold text-sky-700">Most popular</p>
    <h2 class="mt-1 text-2xl font-bold">₹4,999 / month</h2>
    <ul class="mt-4 divide-y divide-slate-200">
      <li class="py-2">Daily doubt classes</li>
      <li class="py-2">Weekly mock tests</li>
      <li class="py-2">Printed notes</li>
    </ul>
    <button class="mt-4 w-full rounded-lg bg-sky-600 py-2 text-white focus-visible:ring-4 focus-visible:ring-sky-300 focus-visible:outline-none">Join now</button>
  </article>
</body>
</html>

ring-2 ring-sky-500 ring-offset-4 highlights the card without changing its size, divide-y separates the features, and the button replaces the default outline with a clearly visible ring only for keyboard focus.

Quick Quiz

1. In Tailwind v4, what colour is a border if you only write border?

2. Why is a ring often better than a border for showing a selected state?

3. Which class adds lines between list items but not after the last one, when placed on the <ul>?

4. What is the v4 equivalent of the v3 class shadow-sm?

Learn Tailwind CSS with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call