Invoice

Invoice SN: 123456789

Payment
Bank transfer
Issued
Due

Invoiced to

Mavis Schmeler
1904 Coolidge St
Brownsville, Texas 78521
United States

Pay to

Miller, Romaguera and Spinka
853 Burwell Heights Road
Nederland, Texas 77627
United States
EIN: 25-3243963
Bank Account Number: 23961707
Invoiced items and totals
ItemQtyUnit priceAmount
Website design (landing page)1$500.00$500.00
Component development2$250.00$500.00
Accessibility audit (hours)4$100.00$400.00
Subtotal$1,400.00
Tax (27%)$378.00
Total due$1,778.00
@use 'sprucecss/scss/spruce' as *;

@page {
  margin: 0;
  size: A4 portrait;
}

.invoice {
  background-color: color('background');
  border-radius: radius('lg');
  box-shadow: 0 0 2.5rem hsl(0deg 0% 0% / 2.5%);
  display: flex;
  flex-direction: column;
  gap: spacer('m');
  padding: spacer-clamp('m', 'l');

  @media print {
    block-size: 29.7cm;
    box-shadow: none;
    inline-size: 21cm;
    padding: 1.25cm;
    print-color-adjust: exact;
  }

  &__header {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: spacer('s') spacer('m');
    justify-content: space-between;
  }

  &__logo {
    --size: 2.5rem;
    block-size: var(--size);
    inline-size: var(--size);
  }

  &__title {
    align-items: flex-end;
    display: flex;
    flex-direction: column;
    gap: spacer('xs');
    margin-block: 0;
  }

  &__serial-number {
    background-color: color('secondary');
    border-radius: radius('sm');
    color: hsl(0deg 0% 100%);
    font-size: config('font-size-base', $typography);
    padding-block: spacer('xxs');
    padding-inline: spacer('xs');
    text-align: center;
  }

  &__highlighted {
    background-color: color('stripe', 'table');
    border-radius: radius('sm');
    display: flex;
    flex-wrap: wrap;
    gap: spacer('xs') spacer('l');
    justify-content: flex-end;
    margin: 0;
    padding: spacer('s') spacer('m');

    div {
      display: flex;
      gap: spacer('xxs');
    }

    dt::after {
      content: ':';
    }

    dd {
      color: color('heading');
      font-weight: 700;
      margin: 0;
    }
  }

  &__meta {
    display: flex;
    flex-direction: column;
    gap: spacer('m');
    justify-content: space-between;

    @include breakpoint('xs') {
      flex-direction: row;
    }

    address {
      font-style: normal;
    }
  }

  &__meta-block {
    @include layout-stack('s');

    h2 {
      font-size: font-size('h3');
    }

    &--align-end {
      @include breakpoint('xs') {
        text-align: end;
      }
    }
  }

  &__footer {
    align-items: center;
    border-block-start: 1px solid color('border');
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    gap: spacer('xs') spacer('m');
    justify-content: space-between;
    margin-block-start: auto;
    padding-block-start: spacer('m');

    @include breakpoint('xs') {
      flex-direction: row;
    }

    &-logo {
      --size: 2rem;
      block-size: var(--size);
      inline-size: var(--size);
    }

    a {
      color: color('text');
      text-decoration: none;
    }
  }

  &__table {
    margin-block-end: spacer('m');

    td,
    th {
      @media print {
        padding: 0.3cm;
      }
    }

    .summary-row {
      background-color: transparent !important;

      th,
      td {
        padding-block: spacer('s') 0;
      }

      th {
        text-align: end;
      }
    }

    .summary-row--total {
      font-size: font-size('h4');

      th,
      td {
        color: color('heading');
        font-weight: 700;
      }
    }
  }

  &__number {
    font-variant-numeric: tabular-nums;
    text-align: end;
    white-space: nowrap;
  }

  &__actions {
    display: flex;
    justify-content: end;

    @media print {
      display: none;
    }
  }
}
<div class="invoice">
    <div class="invoice__header">
        <img class="invoice__logo" src="/img/cone-logo.svg" alt="Cone" height="48" width="48">
        <h1 class="invoice__title">
            Invoice
            <span class="invoice__serial-number">SN: 123456789</span>
        </h1>
    </div>
    <dl class="invoice__highlighted">
        <div>
            <dt>Payment</dt>
            <dd>Bank transfer</dd>
        </div>
        <div>
            <dt>Issued</dt>
            <dd><time datetime="2026-09-13">September 13, 2026</time></dd>
        </div>
        <div>
            <dt>Due</dt>
            <dd><time datetime="2026-09-27">September 27, 2026</time></dd>
        </div>
    </dl>
    <div class="invoice__meta">
        <div class="invoice__meta-block">
            <h2>Invoiced to</h2>
            <address>
                Mavis Schmeler <br/>
                1904 Coolidge St <br/>
                Brownsville, Texas 78521 <br/>
                United States <br/>
            </address>
        </div>
        <div class="invoice__meta-block invoice__meta-block--align-end">
            <h2>Pay to</h2>
            <address>
                <strong>Miller, Romaguera and Spinka</strong> <br/>
                853 Burwell Heights Road <br/>
                Nederland, Texas 77627 <br/>
                United States <br/>
                <strong>EIN:</strong> 25-3243963 <br/>
                <strong>Bank Account Number:</strong> 23961707
            </address>
        </div>
    </div>
    <div class="table-responsive">
        <table class="table table--rounded table--striped table--clear-border invoice__table">
            <caption class="sr-only">Invoiced items and totals</caption>
            <thead>
                <tr>
                    <th scope="col">Item</th>
                    <th class="invoice__number" scope="col">Qty</th>
                    <th class="invoice__number" scope="col">Unit price</th>
                    <th class="invoice__number" scope="col">Amount</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Website design (landing page)</td>
                    <td class="invoice__number">1</td>
                    <td class="invoice__number">$500.00</td>
                    <td class="invoice__number">$500.00</td>
                </tr>
                <tr>
                    <td>Component development</td>
                    <td class="invoice__number">2</td>
                    <td class="invoice__number">$250.00</td>
                    <td class="invoice__number">$500.00</td>
                </tr>
                <tr>
                    <td>Accessibility audit (hours)</td>
                    <td class="invoice__number">4</td>
                    <td class="invoice__number">$100.00</td>
                    <td class="invoice__number">$400.00</td>
                </tr>
            </tbody>
            <tfoot>
                <tr class="summary-row">
                    <th colspan="3" scope="row">Subtotal</th>
                    <td class="invoice__number">$1,400.00</td>
                </tr>
                <tr class="summary-row">
                    <th colspan="3" scope="row">Tax (27%)</th>
                    <td class="invoice__number">$378.00</td>
                </tr>
                <tr class="summary-row summary-row--total">
                    <th colspan="3" scope="row">Total due</th>
                    <td class="invoice__number">$1,778.00</td>
                </tr>
            </tfoot>
        </table>
    </div>
    <div class="invoice__actions">
        <button class="btn btn--primary btn--sm" type="button" data-invoice-print>Print or save as PDF</button>
    </div>
    <div class="invoice__footer">
        <img class="invoice__footer-logo" src="/img/cone-logo.svg" alt="Cone" height="48" width="48"/>
        <a href="mailto:hello@conedevelopment.com">hello@conedevelopment.com</a>
        <a href="tel:+1-512-555-5555">+1-512-555-5555</a>
    </div>
</div>
document.querySelectorAll('[data-invoice-print]').forEach((button) => {
  // The print dialog also offers "Save as PDF"; the print styles size the invoice to A4.
  button.addEventListener('click', () => window.print());
});

Invoice

A print-ready invoice: header with the serial number, payment details, the addresses, an itemized table with the totals and a footer with the contact details. It looks good on screen and prints (or saves as PDF) on an A4 page.

Anatomy

  • .invoice__header with the logo and the title (__title, __serial-number).
  • .invoice__highlighted is a description list for the payment method and the dates (time elements).
  • .invoice__meta holds the two address blocks (__meta-block, --align-end).
  • .invoice__table is a Spruce table: the items in tbody, the subtotal, tax and total in tfoot. Numbers use .invoice__number.
  • .invoice__actions has a print button, hidden when printing; .invoice__footer has the contact details.

Accessibility

  • The table has a (visually hidden) caption, column headers with scope="col" and the total rows use th scope="row", so every amount is read with its label.
  • The tax row says what it is ("Tax (27%)") and shows the amount, not only the rate.

Technical Details

  • The numbers are aligned to the end with tabular-nums, so the digits line up.
  • @page sets an A4 portrait page with no margin, and the print styles size the invoice to 21 × 29.7 cm with print-color-adjust: exact for the backgrounds. The print button calls window.print(); the dialog offers "Save as PDF" too.
  • The legal requirements of an invoice differ by country (tax IDs, wording, numbering); use this as a starting point.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.