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.
#Related
- SurfaceTrays, sheets and wells: the material ladder every component is built on.
- ButtonA raised control that lifts on hover and sinks when pressed.
- HeadingA title in the ink of the page, with the line over it and the paragraph under it.
- InputText fields cut into the surface, with labels, hints, errors and groups.