Skip to content

Gallery / buttons / Border-draw button

Border-draw button

Button whose border draws itself around the label on hover

buttons intermediate buttonborderdrawhover
Live preview

Techniques: pathLength · stroke-dashoffset · transition-reversal · letter-spacing

Customizeupdates preview, code & clipboard
#7F77DD
16px
0.6s
Code snippets/buttons/btn-border-draw.html
<!--
  ============================================================
  SVGarden — https://www.svgarden.dev
  Author : Simon-Pierre Boucher
  Contact: contact@spboucher.ai
  File   : snippets/buttons/btn-border-draw.html
  Desc   : Button whose border draws itself around the label on hover
  ============================================================
-->
<button class="sg-btn-border-draw" type="button" style="--sg-color:#7F77DD; --sg-size:16px; --sg-duration:0.6s;">
  <svg viewBox="0 0 100 40" preserveAspectRatio="none" aria-hidden="true" focusable="false">
    <rect class="sg-btn-border-draw-track" x="1.5" y="1.5" width="97" height="37" rx="9" pathLength="100" />
    <rect class="sg-btn-border-draw-ink"   x="1.5" y="1.5" width="97" height="37" rx="9" pathLength="100" />
  </svg>
  <span class="sg-btn-border-draw-label">Draw me in</span>
</button>
<style>
  .sg-btn-border-draw {
    position: relative;
    appearance: none;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--sg-size);
    font-weight: 600;
    padding: 0.75em 1.6em;
    cursor: pointer;
  }
  .sg-btn-border-draw svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
  }
  .sg-btn-border-draw rect {
    /* no non-scaling-stroke here: Chromium computes dash patterns in screen
       space with it, which breaks the pathLength=100 normalization */
    fill: none;
    stroke: var(--sg-color);
    stroke-width: 2;
    stroke-linecap: round;
  }
  .sg-btn-border-draw-track {
    opacity: 0.25;
  }
  .sg-btn-border-draw-ink {
    /* gap 102 > pathLength so the round end-caps never bleed onto the path at rest */
    stroke-dasharray: 100 102;
    stroke-dashoffset: 101;
    transition: stroke-dashoffset var(--sg-duration) ease-in-out;
  }
  .sg-btn-border-draw-label {
    letter-spacing: 0.02em;
    transition: letter-spacing var(--sg-duration) ease;
  }
  .sg-btn-border-draw:hover .sg-btn-border-draw-ink,
  .sg-btn-border-draw:focus-visible .sg-btn-border-draw-ink {
    stroke-dashoffset: 0;
  }
  .sg-btn-border-draw:hover .sg-btn-border-draw-label,
  .sg-btn-border-draw:focus-visible .sg-btn-border-draw-label {
    letter-spacing: 0.09em;
  }
</style>

More buttons