Marching Border
cubby-ui/marching-borderFreeComponent
A marching-border component.
Live preview
live · rendered by the registry
Rendered by cubby-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://cubby-ui.dev/r/marching-border.jsonSource
1"use client";23import * as React from "react";4import { cn } from "@/lib/utils";56import "./marching-border.css";78export type MarchingBorderProps = React.ComponentProps<"svg"> & {9 /** Stroke thickness in pixels. */10 strokeWidth?: number;11 /** Dash length as a percentage of the path's perimeter. */12 dash?: number;13 /** Gap length as a percentage of the path's perimeter. */14 gap?: number;15 /**16 * Seconds per dash-cycle. One cycle = one dash + one gap traversal,17 * which is the minimum seamless time-loop.18 */19 duration?: number;20};2122/**23 * Builds the `d` for a rounded-rect path starting at the midpoint of the top24 * edge, so any residual subpixel seam falls on a straight side (invisible)25 * rather than at a corner. `inset` shifts coordinates inward by half the stroke26 * so the stroke sits inside the SVG box instead of clipping at the edges.27 */28function buildRoundedRectPath(29 width: number,30 height: number,31 radius: number,32 inset: number,33): string {34 const innerW = width - 2 * inset;35 const innerH = height - 2 * inset;36 if (innerW <= 0 || innerH <= 0) return "";37 const r = Math.min(radius, innerW / 2, innerH / 2);38 const left = inset;39 const top = inset;40 const right = inset + innerW;41 const bottom = inset + innerH;42 // Round to 2 decimals to keep `d` compact; 0.01px is sub-visible so corner43 // alignment with the parent's border-radius is unaffected.44 const f = (n: number) => Math.round(n * 100) / 100;45 return [46 `M ${f(left + innerW / 2)} ${f(top)}`,47 `L ${f(right - r)} ${f(top)}`,48 `A ${f(r)} ${f(r)} 0 0 1 ${f(right)} ${f(top + r)}`,49 `L ${f(right)} ${f(bottom - r)}`,50 `A ${f(r)} ${f(r)} 0 0 1 ${f(right - r)} ${f(bottom)}`,51 `L ${f(left + r)} ${f(bottom)}`,52 `A ${f(r)} ${f(r)} 0 0 1 ${f(left)} ${f(bottom - r)}`,53 `L ${f(left)} ${f(top + r)}`,54 `A ${f(r)} ${f(r)} 0 0 1 ${f(left + r)} ${f(top)}`,55 "Z",56 ].join(" ");57}5859/**60 * Marching-ants dashed border, drawn as an absolutely-positioned SVG overlay61 * outside the wrapped element's box model so toggling it causes zero layout62 * shift. Parent must be positioned and should have a `rounded-*` class to63 * conform to. The SVG defaults to `rounded-[inherit]`, so it adopts the64 * parent's corner radius automatically; pass a `rounded-*` class to override.65 *66 * Seam-free loop via two techniques: (1) `pathLength` is rounded to a whole67// … truncated
Files it writes
More from cubby-ui
All 79 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | cubby-ui | Components | Free | 2 deps | |
| Alertalert | cubby-ui | Components | Free | 1 dep | |
| Alert-dialogalert-dialog | cubby-ui | Components | Free | 2 deps | |
| Aspect-ratioaspect-ratio | cubby-ui | Components | Free | no deps | |
| Autocompleteautocomplete | cubby-ui | Components | Free | 2 deps | |
| Avataravatar | cubby-ui | Components | Free | 1 dep | |
| Badgebadge | cubby-ui | Components | Free | 1 dep | |
| Base Drawerbase-drawer | cubby-ui | Components | Free | 2 deps |
