Navigation

v0.0.4
Marketing blocks

Call to action

The last ask of a page, on a surface of its own.

A call to action is the last ask of a page: after the argument, one more chance to act on it. It gets a surface of its own so it reads as an ending. This one is a sheet of ink, the page's strongest surface, kept for exactly this.

Call to action

<section class="container-inline px-lg py-4xl" aria-labelledby="cta-title">  <div class="sheet sheet-inverse flex flex-col items-center gap-lg max-w(1040) mx-auto px-lg py-3xl text-center">    <h2 class="heading heading-2xl fg-text-inverse max-w(560)" id="cta-title">Your next push could already be live.</h2>    <p class="lead max-w(480) fg-text-inverse">Connect a repository and deploy in under a minute. Free for personal projects.</p>    <div class="flex flex-wrap justify-center gap-sm">      <a class="btn btn-lg" href="#">Start deploying</a>      <a class="btn btn-quiet btn-lg fg-text-inverse" href="#">Talk to sales        <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">          <path d="M5 12h14M13 6l6 6-6 6" />        </svg>      </a>    </div>  </div></section>

Blocks are markup to copy. They take the page's own text color and size; the previews set fg-text-body text-sm on the body. Each block is a size container, so it reflows by its own width.

#What is in it

  • sheet sheet-inverse. Ink on moonstone and pearl on obsidian, with the same fall of light as a primary button. Use one on a page.
  • Inverse ink on the words. The heading and the lead take fg-text-inverse; a utility comes after the heading's own color.
  • A default button as the action. On ink, the ordinary raised button is the brightest thing in view. A primary button would be ink on ink.
  • One sentence and one action, with a quiet second for the visitor who is not ready.

#Quiet

When the page already ends strongly, or the same ask repeats on every page, use the ordinary materials: a sheet in a tray, words at the start and buttons at the end. flex flex-wrap justify-between drops the buttons under the words when they no longer fit.

Quiet

<section class="container-inline px-lg py-4xl" aria-labelledby="cta-quiet-title">  <div class="tray max-w(1040) mx-auto">    <div class="sheet flex flex-wrap items-center justify-between gap-lg p-xl">      <div class="flex flex-col gap-xs">        <h2 class="heading heading-lg" id="cta-quiet-title">Ready when you are.</h2>        <p class="m(0) leading-md">Deploy your first project in under a minute. No card needed.</p>      </div>      <div class="flex flex-wrap gap-sm">        <a class="btn btn-primary" href="#">Start deploying</a>        <a class="btn" href="#">Read the docs</a>      </div>    </div>  </div></section>

#With a field

When the action is an address, put the field and its button in a wrapping row. grow(1) basis(200) lets the field take the row and gives it 200px before the button drops below.

With a field

<section class="container-inline px-lg py-4xl" aria-labelledby="cta-form-title">  <div class="flex flex-col items-center gap-lg max-w(520) mx-auto text-center">    <h2 class="heading heading-2xl" id="cta-form-title">One email when something ships.</h2>    <p class="lead">The changelog, about twice a month. Nothing else, and one click to stop.</p>    <form class="flex flex-wrap gap-xs w-full max-w(420)">      <input class="input grow(1) basis(200)" type="email" name="email" placeholder="you@example.com" aria-label="Email" autocomplete="email" required>      <button class="btn btn-primary">Subscribe</button>    </form>  </div></section>

#Accessibility

  • The inverse sheet keeps full text contrast in both schemes: its ink and its text are the theme's own inverse pair.
  • A field needs a name. Here it is aria-label="Email"; a visible label is better when there is room.
  • Say what happens after the click: "Start deploying" is a promise, "Submit" is not.