Skip to content

Tailwind CSS footer: 5 responsive examples to copy

Published 9 min read

On this page

A footer is the part of a page nobody designs first and everybody notices when it's broken. Links wrap badly on a phone, the footer floats halfway up a short page, or the gray copyright text is too faint to read. This post has five responsive footer examples built with Tailwind CSS v4 that you can copy into a project, plus the two things most footer snippets skip: keeping the footer at the bottom of short pages and getting the markup right for screen readers.

Every example is plain HTML with Tailwind classes. No JavaScript, no plugins. They assume Tailwind v4 with the default theme, so class names like size-5 and min-h-dvh work out of the box. If you built the header with our responsive navigation menu tutorial, these footers are its counterpart at the other end of the page.

Use this for a personal site, a landing page or a small product with only a handful of pages. Everything sits in one centered column on mobile and spreads into a row on wider screens: brand and copyright on the left, links in the middle, social icons on the right.

<footer class="border-t border-gray-200 bg-white">
  <div class="mx-auto flex max-w-6xl flex-col items-center gap-6 px-6 py-10 md:flex-row md:justify-between">
    <p class="text-sm text-gray-600">&copy; 2026 Acme, Inc.</p>

    <nav aria-label="Footer">
      <ul class="flex flex-wrap justify-center gap-x-6 gap-y-2 text-sm">
        <li><a href="/about" class="text-gray-600 hover:text-gray-900">About</a></li>
        <li><a href="/blog" class="text-gray-600 hover:text-gray-900">Blog</a></li>
        <li><a href="/pricing" class="text-gray-600 hover:text-gray-900">Pricing</a></li>
        <li><a href="/contact" class="text-gray-600 hover:text-gray-900">Contact</a></li>
      </ul>
    </nav>

    <div class="flex gap-2">
      <a href="https://github.com/acme" aria-label="Acme on GitHub"
         class="rounded-md p-2 text-gray-500 hover:text-gray-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900">
        <svg class="size-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
          <path d="M12 2a10 10 0 0 0-3.16 19.49c.5.09.68-.22.68-.48v-1.7c-2.78.6-3.37-1.34-3.37-1.34-.45-1.16-1.11-1.47-1.11-1.47-.91-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.9 1.52 2.34 1.08 2.91.83.09-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.94 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.64 0 0 .84-.27 2.75 1.02a9.6 9.6 0 0 1 5 0c1.91-1.29 2.75-1.02 2.75-1.02.55 1.37.2 2.39.1 2.64.64.7 1.03 1.59 1.03 2.68 0 3.84-2.34 4.68-4.57 4.93.36.31.68.92.68 1.85v2.74c0 .27.18.58.69.48A10 10 0 0 0 12 2Z"/>
        </svg>
      </a>
      <a href="https://x.com/acme" aria-label="Acme on X"
         class="rounded-md p-2 text-gray-500 hover:text-gray-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900">
        <svg class="size-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
          <path d="M17.75 3h3.07l-6.7 7.66L22 21h-6.17l-4.83-6.32L5.47 21H2.4l7.17-8.2L2 3h6.33l4.37 5.77L17.75 3Zm-1.08 16.2h1.7L7.4 4.73H5.58L16.67 19.2Z"/>
        </svg>
      </a>
    </div>
  </div>
</footer>

Key classes: flex-col items-center stacks everything on mobile and md:flex-row md:justify-between turns it into a row from 768px up. flex-wrap with separate gap-x-6 gap-y-2 lets the links wrap onto a second line without the rows sticking together. size-5 sets width and height in one class, and p-2 on the icon links makes the tap area bigger than the 20px icon. The SVG gets aria-hidden="true" because the link's aria-label already names it.

This is the classic SaaS or company footer: a brand column with a short description, then three or four columns of links grouped by topic. Use it when the site has enough pages that a single row of links would get long, or when you want the footer to double as a sitemap.

<footer class="border-t border-gray-200 bg-gray-50">
  <div class="mx-auto max-w-6xl px-6 py-16">
    <div class="grid gap-12 lg:grid-cols-3">
      <div>
        <a href="/" class="text-lg font-semibold text-gray-900">Acme</a>
        <p class="mt-3 max-w-xs text-sm text-gray-600">
          Invoicing software for small teams. Send, track and get paid.
        </p>
      </div>

      <nav aria-label="Footer" class="grid grid-cols-2 gap-8 sm:grid-cols-3 lg:col-span-2">
        <div>
          <h2 class="text-sm font-semibold text-gray-900">Product</h2>
          <ul class="mt-4 space-y-3 text-sm">
            <li><a href="/features" class="text-gray-600 hover:text-gray-900">Features</a></li>
            <li><a href="/pricing" class="text-gray-600 hover:text-gray-900">Pricing</a></li>
            <li><a href="/changelog" class="text-gray-600 hover:text-gray-900">Changelog</a></li>
          </ul>
        </div>
        <div>
          <h2 class="text-sm font-semibold text-gray-900">Company</h2>
          <ul class="mt-4 space-y-3 text-sm">
            <li><a href="/about" class="text-gray-600 hover:text-gray-900">About</a></li>
            <li><a href="/blog" class="text-gray-600 hover:text-gray-900">Blog</a></li>
            <li><a href="/careers" class="text-gray-600 hover:text-gray-900">Careers</a></li>
          </ul>
        </div>
        <div>
          <h2 class="text-sm font-semibold text-gray-900">Legal</h2>
          <ul class="mt-4 space-y-3 text-sm">
            <li><a href="/privacy" class="text-gray-600 hover:text-gray-900">Privacy</a></li>
            <li><a href="/terms" class="text-gray-600 hover:text-gray-900">Terms</a></li>
            <li><a href="/cookies" class="text-gray-600 hover:text-gray-900">Cookies</a></li>
          </ul>
        </div>
      </nav>
    </div>

    <p class="mt-12 border-t border-gray-200 pt-8 text-sm text-gray-600">
      &copy; 2026 Acme, Inc. All rights reserved.
    </p>
  </div>
</footer>

Key classes: the outer grid lg:grid-cols-3 puts the brand column next to the links only on large screens. The link columns have their own grid: grid-cols-2 on phones (two columns of short words fit fine at 375px), sm:grid-cols-3 from 640px, and lg:col-span-2 so they take two thirds of the width next to the brand. space-y-3 spaces the list items. If you have four link groups, switch to sm:grid-cols-4, and keep grid-cols-2 on mobile so they pair up instead of leaving one column on its own.

The column titles are <h2> elements here. Use whatever heading level fits your page outline, or a plain <p> if you'd rather keep footer labels out of the heading structure. Both are fine as long as you pick one on purpose.

Use this when you have a newsletter or product updates and the footer is the natural place to ask for an email address. People who scroll all the way down are the ones most likely to sign up. The form sits next to the links on desktop and drops below them on mobile, with the input and button stacked on narrow screens.

<footer class="border-t border-gray-200 bg-white">
  <div class="mx-auto grid max-w-6xl gap-10 px-6 py-14 md:grid-cols-2">
    <nav aria-label="Footer">
      <a href="/" class="text-lg font-semibold text-gray-900">Acme</a>
      <ul class="mt-6 grid grid-cols-2 gap-3 text-sm">
        <li><a href="/features" class="text-gray-600 hover:text-gray-900">Features</a></li>
        <li><a href="/pricing" class="text-gray-600 hover:text-gray-900">Pricing</a></li>
        <li><a href="/blog" class="text-gray-600 hover:text-gray-900">Blog</a></li>
        <li><a href="/contact" class="text-gray-600 hover:text-gray-900">Contact</a></li>
      </ul>
    </nav>

    <form action="/subscribe" method="post">
      <label for="footer-email" class="text-sm font-semibold text-gray-900">
        Get product updates
      </label>
      <p id="footer-email-hint" class="mt-1 text-sm text-gray-600">
        One email a month. Unsubscribe anytime.
      </p>
      <div class="mt-4 flex flex-col gap-3 sm:flex-row">
        <input id="footer-email" name="email" type="email" required autocomplete="email"
               aria-describedby="footer-email-hint" placeholder="you@example.com"
               class="min-w-0 flex-1 rounded-md border border-gray-300 px-3 py-2 text-sm text-gray-900 placeholder:text-gray-500 focus:border-gray-900 focus:outline-none">
        <button type="submit"
                class="rounded-md bg-gray-900 px-4 py-2 text-sm font-semibold text-white hover:bg-gray-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900">
          Subscribe
        </button>
      </div>
    </form>
  </div>

  <p class="border-t border-gray-200 py-6 text-center text-sm text-gray-600">
    &copy; 2026 Acme, Inc.
  </p>
</footer>

Key classes: flex flex-col sm:flex-row stacks the input and button on phones and puts them side by side from 640px. flex-1 makes the input take the remaining space, and min-w-0 stops it from overflowing its container, because a flex item won't shrink below its content width by default. placeholder:text-gray-500 keeps the placeholder readable. Note the real <label>: the placeholder is an example, not a label, and it disappears as soon as someone starts typing.

Use this on marketing pages where the footer is the last chance to convert. A call-to-action band sits right above the links and both share a dark background, so the page ends on one solid block instead of trailing off.

<footer class="bg-gray-900">
  <div class="mx-auto max-w-6xl px-6">
    <div class="flex flex-col items-start gap-6 border-b border-gray-800 py-16 md:flex-row md:items-center md:justify-between">
      <div>
        <h2 class="text-2xl font-semibold text-white">Ready to send your first invoice?</h2>
        <p class="mt-2 text-gray-400">Free for your first 10 clients. No credit card needed.</p>
      </div>
      <a href="/signup"
         class="shrink-0 rounded-md bg-white px-5 py-3 text-sm font-semibold text-gray-900 hover:bg-gray-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white">
        Start for free
      </a>
    </div>

    <div class="flex flex-col gap-6 py-10 md:flex-row md:items-center md:justify-between">
      <nav aria-label="Footer">
        <ul class="flex flex-wrap gap-x-6 gap-y-2 text-sm">
          <li><a href="/features" class="text-gray-400 hover:text-white">Features</a></li>
          <li><a href="/pricing" class="text-gray-400 hover:text-white">Pricing</a></li>
          <li><a href="/docs" class="text-gray-400 hover:text-white">Docs</a></li>
          <li><a href="/privacy" class="text-gray-400 hover:text-white">Privacy</a></li>
        </ul>
      </nav>
      <p class="text-sm text-gray-400">&copy; 2026 Acme, Inc.</p>
    </div>
  </div>
</footer>

Key classes: bg-gray-900 with text-gray-400 for secondary text and text-white for the heading. The divider is border-gray-800, one step lighter than the background, which is enough to see without drawing attention. shrink-0 on the button keeps it from getting squeezed when the heading is long. items-start on mobile left-aligns the button under the text instead of stretching it full width; drop it if you want a full-width button on phones.

Watch the gray you pick here. text-gray-400 on bg-gray-900 has enough contrast for body text; text-gray-500 does not. More on that in the accessibility section below. If you want a different tint than gray, the same steps apply to slate, zinc or neutral, and our Tailwind CSS colors page lists every shade.

Inside an app, a dashboard or a docs site, the footer should get out of the way. One line, small text, a version number or status link if you have one. Use this anywhere people come to work rather than to browse.

<footer class="border-t border-gray-200">
  <div class="mx-auto flex max-w-6xl flex-wrap items-center justify-between gap-x-6 gap-y-2 px-6 py-4 text-sm text-gray-500">
    <p>&copy; 2026 Acme &middot; v4.2.0</p>
    <nav aria-label="Footer">
      <ul class="flex flex-wrap gap-x-4 gap-y-1">
        <li><a href="/status" class="hover:text-gray-900">Status</a></li>
        <li><a href="/docs" class="hover:text-gray-900">Docs</a></li>
        <li><a href="/support" class="hover:text-gray-900">Support</a></li>
      </ul>
    </nav>
  </div>
</footer>

Key classes: flex flex-wrap justify-between puts the copyright and links at opposite ends, and flex-wrap lets the links drop to a second line on a narrow screen instead of overflowing. Setting text-sm text-gray-500 on the container means the links inherit it, so they only need a hover color. text-gray-500 on white passes the 4.5:1 contrast minimum, but only just, so don't go lighter.

On a page with little content, a footer sits right below that content, which can be halfway up the screen. What you usually want is a "sticky footer": at the bottom of the viewport when the page is short, and pushed down normally when it's long. This is not position: sticky or fixed; the footer stays in the normal flow. You only need to make the page at least as tall as the screen and give the extra space to the main content.

<body class="flex min-h-dvh flex-col">
  <header>...</header>
  <main class="flex-1">...</main>
  <footer>...</footer>
</body>

min-h-dvh makes the body at least one screen tall, flex-col stacks the children, and flex-1 on <main> lets it grow to fill whatever height is left. If you can't put a class on <main>, for example because a layout component renders it, put mt-auto on the footer instead. An automatic top margin in a flex column takes up all free space above the footer, which pushes it down just the same.

<body class="grid min-h-dvh grid-rows-[auto_1fr_auto]">
  <header>...</header>
  <main>...</main>
  <footer>...</footer>
</body>

Three rows: the header and footer take the height of their content (auto), the main row gets the rest (1fr). The underscores in the arbitrary value become spaces in the CSS. This version needs no class on the children, but it does expect exactly three direct children. A skip link or a cookie banner as an extra child of <body> will end up in a row of its own, so wrap the three parts in a <div> if your body has more in it.

Why dvh instead of vh

On mobile browsers, 100vh is the height of the viewport with the address bar hidden. When the page first loads, the address bar is visible, so a min-h-screen page (100vh) is slightly taller than the screen and the footer starts just below the fold. The dvh unit (dynamic viewport height) follows the visible area as the browser bars show and hide, so the footer lands at the actual bottom of the screen. Tailwind v4 has min-h-dvh, min-h-svh (small viewport, bars visible) and min-h-lvh (large viewport, bars hidden). min-h-dvh is the right default for a sticky footer. On desktop all three behave the same as vh.

A few details make a footer work for keyboard and screen reader users. None of them change how it looks.

  • Use <footer>. When it isn't nested inside <main>, <article>, <section>, <aside> or <nav>, screen readers expose it as the page's "contentinfo" landmark, so users can jump straight to it.
  • Label the navigation. Your page probably has two <nav> elements, one in the header and one in the footer. aria-label="Footer" tells them apart in a screen reader's landmark list. Don't add the word "navigation" to the label; it's announced already.
  • Put links in a list. A <ul> of links tells screen reader users how many links there are before they start. Tailwind's preflight removes the bullets and padding, so the list costs you nothing visually.
  • Check the contrast of gray text. Footers are where low-contrast gray text tends to pile up. With Tailwind v4's default colors: text-gray-400 on bg-gray-900 is about 6.8:1 and passes WCAG AA (4.5:1 for normal text), text-gray-500 on bg-gray-900 is about 3.7:1 and fails. On a white background it's the other way around: text-gray-500 is about 4.8:1 and passes, text-gray-400 is about 2.6:1 and fails. Test your own combinations with a contrast checker, especially if you use a custom palette.
  • Give links room to tap. Small footer links that sit close together are easy to miss on a phone. WCAG 2.2 asks for targets of at least 24 by 24 CSS pixels, or enough space around smaller ones. The gap-y-2 and space-y-3 in the examples give that space; for icon-only links, padding such as p-2 around a size-5 icon gives a 36px target.
  • Name icon links. An icon link without text needs an aria-label (or visually hidden text with sr-only), and the SVG itself should be aria-hidden="true".
  • Keep focus visible. If you remove default outlines, add focus-visible: styles back so keyboard users can see where they are.
  • Keep the year current. A copyright line that still says 2023 makes a site look abandoned. On a static site, have your build output the year, for example {new Date().getFullYear()} in an Astro or JSX template, and rebuild at least once a year.

If you'd rather start from a complete page than paste footers in one by one, our free Tailwind templates with full footers include all of the above in context.

FAQ#

Put flex min-h-dvh flex-col on the <body> (or a wrapper div) and flex-1 on <main>. The main content grows to fill the screen, so the footer sits at the bottom on short pages and below the content on long ones. Alternatively, use grid min-h-dvh grid-rows-[auto_1fr_auto] on the wrapper. If you want the footer always visible while scrolling, that's fixed bottom-0 inset-x-0, but for a page footer that's rarely what you want.

Start with the mobile layout, usually a single stacked column (flex flex-col or a one-column grid), and add breakpoint prefixes for wider screens: md:flex-row md:justify-between for a single row, or grid-cols-2 md:grid-cols-4 for link columns. Use flex-wrap with gap-x-* and gap-y-* on link rows so they wrap cleanly instead of overflowing.

Yes. A page-level <footer> becomes a landmark that screen reader users can jump to, and it costs nothing. Put your links inside a <nav aria-label="Footer"> with a <ul>, and keep the copyright line and any contact details outside the nav. The Tailwind docs on responsive design cover the breakpoint prefixes used throughout this post.

Build faster with Tailwind CSS

Admin themes, website templates and landing pages. Almost all of it free.

Browse the library