I wanted a checkmark that draws itself in on success, the classic stroke-dasharray trick, but every generated version either looped forever, drew at a constant robotic speed, or flashed the fully-drawn state for a frame before starting.
The fixes I had to spell out: compute the path length and set dasharray/offset to it, use animation-fill-mode: forwards so it holds, add a tiny delay so the initial hidden state paints first, and gate the whole thing behind reduced-motion (where it just shows the finished check).
No answers needed, just leaving this prompt here for the next person searching "svg self draw once not looping".
Create an inline SVG checkmark that draws itself once on load and holds the finished state. No JS, no libraries.
- Single `<path>` for the check, `fill: none`, `stroke-width: 3`, `stroke-linecap: round`, `stroke-linejoin: round`.
- Animate with `stroke-dasharray` and `stroke-dashoffset`: set both to the path's total length (state it explicitly, e.g. ~48 units) so the line is fully hidden at 0%.
- Animation: `draw 500ms cubic-bezier(0.65, 0, 0.35, 1) 80ms forwards`. The 80ms delay lets the hidden state paint first (no flash of the finished check). `forwards` holds it drawn. It must NOT loop.
- Add a subtle `<circle>` that scales from 0.9 to 1 on the same timeline for a little pop, transform-origin center.
- Inside `@media (prefers-reduced-motion: reduce)`: no animation, checkmark shown fully drawn and static.
Before the code, state the path length you used and how you'd recompute it if the path changes.