A Tailwind HTML template in one file

One file, no build step, and a layout that already handles a header, a card grid, a table and dark mode. The trade-offs of the browser build are at the end.

A Tailwind HTML template that works with no build step is one file: the browser build in a script tag, then markup carrying utility classes.

Here is a starter you can paste and edit. It has a header, a card grid, a table and dark mode.

<!doctype html>
<html lang="en" class="h-full">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Weekly report</title>
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full bg-slate-50 text-slate-900 dark:bg-slate-900 dark:text-slate-100">

  <header class="border-b border-slate-200 dark:border-slate-700">
    <div class="mx-auto max-w-5xl px-6 py-5 flex items-baseline justify-between">
      <h1 class="text-xl font-semibold">Weekly report</h1>
      <p class="text-sm text-slate-500">Week 38</p>
    </div>
  </header>

  <main class="mx-auto max-w-5xl px-6 py-8 space-y-8">

    <section class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
      <div class="rounded-lg border border-slate-200 dark:border-slate-700 p-5">
        <p class="text-sm text-slate-500">Active accounts</p>
        <p class="mt-1 text-3xl font-semibold tabular-nums">1,284</p>
      </div>
      <div class="rounded-lg border border-slate-200 dark:border-slate-700 p-5">
        <p class="text-sm text-slate-500">Open tickets</p>
        <p class="mt-1 text-3xl font-semibold tabular-nums">37</p>
      </div>
      <div class="rounded-lg border border-slate-200 dark:border-slate-700 p-5">
        <p class="text-sm text-slate-500">Median first reply</p>
        <p class="mt-1 text-3xl font-semibold tabular-nums">42m</p>
      </div>
    </section>

    <section>
      <h2 class="text-base font-semibold mb-3">By team</h2>
      <div class="overflow-x-auto rounded-lg border border-slate-200 dark:border-slate-700">
        <table class="w-full text-sm">
          <thead class="bg-slate-100 dark:bg-slate-800 text-left">
            <tr>
              <th scope="col" class="px-4 py-2 font-medium">Team</th>
              <th scope="col" class="px-4 py-2 font-medium">Tickets</th>
              <th scope="col" class="px-4 py-2 font-medium">Trend</th>
            </tr>
          </thead>
          <tbody class="divide-y divide-slate-200 dark:divide-slate-700">
            <tr><td class="px-4 py-2">Billing</td><td class="px-4 py-2 tabular-nums">14</td><td class="px-4 py-2 text-emerald-600">down</td></tr>
            <tr><td class="px-4 py-2">Onboarding</td><td class="px-4 py-2 tabular-nums">12</td><td class="px-4 py-2 text-rose-600">up</td></tr>
          </tbody>
        </table>
      </div>
    </section>

  </main>
</body>
</html>
The template rendering, showing the header, three cards and the table.
The template rendering, showing the header, three cards and the table.

What the classes in that file are doing

Class group Job Change it to
mx-auto max-w-5xl px-6 Centred column with side padding max-w-3xl for reading, max-w-7xl for dashboards
grid gap-4 sm:grid-cols-2 lg:grid-cols-3 Cards reflow by width Any column count per breakpoint
rounded-lg border p-5 The card itself shadow-sm instead of border
dark:bg-slate-900 Dark variant of a rule Any class can take dark:
tabular-nums Digits of equal width Keep it anywhere numbers stack
divide-y Lines between children divide-x for columns

tabular-nums is the one worth remembering. Without it, a column of figures wobbles because the digits have different widths.

How the responsive part works

The template has no media queries in it, and it still reflows correctly. That is what the breakpoint prefixes are doing.

A class with no prefix applies at every width. A class with sm:, md: or lg: applies from that width upward and stays applied above it.

<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">

Read that as one column by default, two from the small breakpoint, three from large. The default case is the phone, which is the right way round for most internal pages.

The same prefixes work on anything, not only layout. text-sm md:text-base, hidden lg:block and px-4 md:px-8 are all valid, and they cover most of what a media query would have done.

One caution. Do not give every element its own set of breakpoints. Let the container reflow and the contents follow, or the page becomes impossible to reason about.

Where the table earns its keep

Dashboards paste badly into narrow screens, and the wrapper above is why this one does not.

overflow-x-auto on a div around the table lets it scroll sideways rather than squashing the columns into unreadable widths. It costs one class and removes the most common mobile complaint.

For tables people scan rather than read, add whitespace-nowrap on the cells that must not wrap, usually dates and figures. Leave the description column free to wrap.

Adding your own colours

The browser build takes a configuration block in the page, placed after the script tag:

<script>
  tailwind.config = {
    theme: {
      extend: {
        colors: { brand: { 500: '#3b6cf0', 600: '#2f57c9' } },
        fontFamily: { sans: ['Inter', 'system-ui', 'sans-serif'] }
      }
    }
  };
</script>

After that, bg-brand-500 and text-brand-600 work like any built-in colour. Define brand values once here rather than writing arbitrary hex values through the markup, which nothing keeps consistent.

The same template after a config block swaps the accent colour for a brand colour.
The same template after a config block swaps the accent colour for a brand colour.

The browser build against a compiled stylesheet

Browser build Compiled
Setup One script tag Node, a config, a build command
Stylesheet size Generated at load Only the classes you used
First paint Short unstyled flash No flash
Works offline No Yes
Suits Prototypes, internal pages, demos Public production sites

The browser build is documented as a development and prototyping convenience, so use it accordingly. For an internal weekly report that five people open, it is the right tool. For a marketing site, compile.

Keeping the markup readable

Long class strings are the standard complaint about Tailwind, and most of it is avoidable.

  1. Order classes consistently, for example layout, then spacing, then colour, then type.
  2. Repeat a card by copying the block, not by inventing a new variant each time.
  3. Pull genuinely repeated patterns into a class with @apply once you are compiling.
  4. Do not mix in a second stylesheet that fights the utilities. Pick one system per page.
  5. Keep arbitrary values rare. w-[327px] is a sign the layout wants a different approach.

The first point matters more than it looks. Consistent order makes a long class string scannable, because your eye learns where to find the colour without reading the whole line.

Editors can enforce it. A class sorting plugin applied on save removes the decision entirely, and it also makes differences between two similar blocks visible in a diff rather than buried in reordered text.

Sharing the finished page

The page depends on that script tag. Copy the file in full, including the <head>, or the classes stop resolving and you get unstyled text.

Paste the complete HTML into a NOS document. It renders as written, dark theme and all, at an address of its own. Then Share, Share link, Create link.

The Tailwind page open from a shared address in a phone browser.
The Tailwind page open from a shared address in a phone browser.

Because the text stays clickable in the document, next week's figures replace this week's at the same link. Turning HTML into a link is that step by itself.

If the page renders plain when you test it, open the file in the HTML file opener. Unstyled output there means the Tailwind script is not travelling with the file, which is the same class of problem as a missing external stylesheet.

Adding Tailwind to an existing HTML file covers retrofitting rather than starting fresh, and a Bootstrap template is the component-based alternative.

Questions people ask

Can I use Tailwind without a build step?

Yes. The browser build is a script tag that generates the classes it finds in the page at load time. It is meant for prototypes, internal pages and demos. For a public production site, the compiled route produces a much smaller stylesheet.

Why does my Tailwind page flash unstyled for a moment?

The browser build has to load and then generate the styles, so there is a short gap. A compiled stylesheet in the head does not have that gap. On an internal page it rarely matters. On a public landing page it is noticeable.

Where do I put custom colours and fonts?

In a configuration block in the page when using the browser build, or in your CSS entry file when compiling. Do not scatter custom hex values through the markup as arbitrary values, since nothing then keeps them consistent.

Does a Tailwind page survive being pasted into a document?

Yes, as long as the script tag that loads Tailwind comes with it. Paste the whole file into a NOS document and it renders as written. If you strip the script tag, every class stops meaning anything and the page collapses to plain text.

Keep reading