Component Library

← Back to gallery

Link and button pair

Category: Buttons · Tags: form-footer, submit, cancel, link, actions

Cancel

How to use it

Use at the bottom of a form: a button for the action that changes data (save, submit, send) and a link for leaving without changes (cancel back to where the user came from). The rule of thumb: if it goes to another URL, it is a link; if it does something on this page, it is a button. Don't style Cancel as a big button next to Save, which makes the two compete. Point the Cancel href at the page the user came from and replace the demo submit handler with your real save.

Accessibility

"Save changes" is a native <button type="submit">, so it submits the form with Enter or a click and is announced as a button; "Cancel" is a real <a href> because it only navigates away, so it is announced as a link and opens in a new tab like any link. Both reach Tab in reading order (primary first) and show a 2px focus outline, and the link keeps its underline so it is recognisable without colour. The demo's submit result is announced in a role="status" line. Text is #ffffff on #1d4ed8 (6.70:1) and the #1e40af hover (8.72:1), the link is #1d4ed8 on #ffffff (6.70:1) and #1e3a8a when hovered (10.36:1), and labels are #0f172a on #ffffff (17.85:1).

Source (copy-ready)

<form class="dcl-formfoot" novalidate>
  <label class="dcl-formfoot__label" for="dcl-formfoot-name">Display name</label>
  <input class="dcl-formfoot__input" id="dcl-formfoot-name" name="display-name" type="text" autocomplete="nickname" value="Sam Rivera">
  <div class="dcl-formfoot__actions">
    <button type="submit" class="dcl-formfoot__save">Save changes</button>
    <a class="dcl-formfoot__cancel" href="../index.html">Cancel</a>
  </div>
  <p class="dcl-formfoot__status" role="status"></p>
</form>
<style>
.dcl-formfoot { display: flex; flex-direction: column; gap: 0.4rem; max-width: 22rem; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-formfoot__label { font-weight: 600; color: #0f172a; background-color: #ffffff; }
.dcl-formfoot__input { min-width: 0; padding: 0.55rem 0.7rem; border: 1px solid #64748b; border-radius: 0.375rem; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-formfoot__input:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 1px; }
.dcl-formfoot__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem; margin-top: 0.75rem; }
.dcl-formfoot__save { min-height: 2.75rem; padding: 0 1.25rem; border: none; border-radius: 0.5rem; cursor: pointer; font: inherit; font-weight: 600; color: #ffffff; background-color: #1d4ed8; }
.dcl-formfoot__save:hover { color: #ffffff; background-color: #1e40af; }
.dcl-formfoot__save:focus-visible { outline: 2px solid #0f172a; outline-offset: 2px; }
.dcl-formfoot__cancel { padding: 0.5rem 0.25rem; text-decoration: underline; text-underline-offset: 0.2em; color: #1d4ed8; background-color: #ffffff; }
.dcl-formfoot__cancel:hover { color: #1e3a8a; background-color: #ffffff; }
.dcl-formfoot__cancel:focus-visible { outline: 2px solid #0f172a; outline-offset: 2px; }
.dcl-formfoot__status { min-height: 1.5em; margin: 0.25rem 0 0; color: #0f172a; background-color: #ffffff; }
</style>
<script>
(function () {
  document.querySelectorAll(".dcl-formfoot").forEach(function (root) {
    if (root.dataset.dclBound) { return; }
    root.dataset.dclBound = "true";
    var status = root.querySelector(".dcl-formfoot__status");
    root.addEventListener("submit", function (event) {
      event.preventDefault();
      if (status) { status.textContent = "Changes saved."; }
    });
  });
})();
</script>

Was this useful? Send feedback.