Border Draw-On
On hover, focus or finger press, a 3 px line runs around the box in four steps from the top-left corner, then pulls back when the state ends.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →
3 usage examples



How it works
The .bdw-box holds four empty <span class="bdw-line">, absolutely positioned on its edges: bdw-top starts at the top-left corner with zero width, bdw-right at the top-right corner with zero height, bdw-bottom at the bottom-right corner, bdw-left at the bottom-left corner. At rest nothing shows: the box has the same background as the page.
In the active state each line grows to 100% of its side in 0.4 s (cubic-bezier(.65, 0, .35, 1) curve), starting 0, 0.4, 0.8 and 1.2 s apart: the top draws left to right, then the right side goes down, the bottom comes back left and the left side climbs up. The whole frame is there after 1.6 s, with a 10 px box-shadow glow. When the state ends the lines retract in the same order, top first.
The active state combines hover, :focus-within (the box itself when it is a link or a button, or a field, link or button inside it) and the bdw-on class, which a 0.8 KB script adds when a finger or pen presses the box and removes at the next press elsewhere. Colour, thickness and the duration of one side are CSS custom properties.
Accessibility
- Silent lines: the four
<span>are empty and markedaria-hidden="true"; only your content is announced. - The drawing is the focus indicator: on a link or button, the box draws itself on keyboard focus and its default focus outline is removed (
outline: noneon:focus-visible). Keep a line colour with strong contrast against the background. Around an input field, the frame draws as soon as the field is active. - Touch: a finger press draws the frame (
bdw-onclass) and it stays until the next press elsewhere, even in WebKit, which has no hover. - Reduced motion: under
prefers-reduced-motion: reducethere is no progressive drawing; the whole frame appears and disappears at once. - macOS Safari: Tab only reaches links if the system setting allows it; Option+Tab always does.
Browser compatibility
CSS (width and height transitions, custom properties, :is() selector: Chrome 88, Firefox 78, Safari 14), plus 0.8 KB of JavaScript for touch. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two copies with only the second one hovered, keyboard focus through a link inside and through the box turned into a link, finger press, 390 px without overflow, reduced motion with no transition, 0 errors.
A browser without :is() ignores the active-state rules: the box stays frameless. Without JavaScript, only a finger press on a box that is neither a link nor a button draws nothing.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0768-root">
<div class="bdw-box">
<span class="bdw-line bdw-top" aria-hidden="true"></span>
<span class="bdw-line bdw-right" aria-hidden="true"></span>
<span class="bdw-line bdw-bottom" aria-hidden="true"></span>
<span class="bdw-line bdw-left" aria-hidden="true"></span>
…
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Line colour (CSS — --bdw-color) |
#6366f1 |
Colour of the four lines, set on .fx-0768-root or a parent. |
Glow (CSS — --bdw-glow) |
rgba(99, 102, 241, .6) |
Colour of the 10 px halo in the active state; transparent for a line without halo. |
Thickness (CSS — --bdw-width) |
3px |
Thickness of all four lines. |
Duration of one side (CSS — --bdw-speed) |
.4s |
Each side takes this long and waits for the previous one: the full lap lasts four times the value. |
Box size (CSS — width / min-height of .bdw-box) |
200 px wide, at least 120 px tall | The lines use percentages: they fit any size. |
Forced active state (HTML — bdw-on class on .bdw-box) |
absent | Keeps the frame drawn, for instance on the current tab or project; adding or removing it replays the drawing. The script only removes the one it added on touch. |
FAQ
border-radius down to 4 px or less so the frame hugs its corners.left: 0 for the top, top: 0 for the right…) and in the order set by its transition-delay. Swap the anchors (right: 0 instead of left: 0) and the delays to change the starting point or the direction.bdw-box class on the card's <a>, keep the four <span> first and your content after them. Hover, Tab and a finger press draw the same frame, and the link stays an ordinary link for screen readers. One .fx-0768-root per card: the touch script only takes the first box of each root.