Writing Text Effect

v1.0

An elegant SVG path animation that mimics handwriting using Framer Motion.

Live Preview
Customize text and font to see the animation.
Mutasim Fuad RimuMutasim Fuad Rimu

Install Dependencies

npx shadcn@latest add https://raw.githubusercontent.com/rimu-7/shadcn-components/main/public/registry/text-writing-effect.json

Component Code

Copy the code below into components/ui/text-writing-effect.tsx

"use client";

import React from "react";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";

export function TextWritingEffect({
  text,
  fontClassName,
  speed = 2,
  color = "currentColor",
  strokeWidth = 1.5,
  className,
  ...props
}) {
  const pathLength = 1000;

  return (
    <div
      className={cn(
        "flex items-center justify-center overflow-hidden w-full h-auto",
        className
      )}
    >
      <motion.svg
        key={`${text}-${fontClassName}`}
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 800 200"
        className="w-full h-full overflow-visible"
        {...props}
      >
        <defs>
          <linearGradient id="textGradient" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stopColor={color} stopOpacity="1" />
            <stop offset="100%" stopColor={color} stopOpacity="0.8" />
          </linearGradient>
        </defs>

        <motion.text
          x="50%"
          y="50%"
          textAnchor="middle"
          dominantBaseline="middle"
          className={cn("text-7xl fill-transparent", fontClassName)}
          style={{ stroke: color }}
          strokeWidth={strokeWidth}
          strokeLinecap="round"
          initial={{
            strokeDasharray: pathLength,
            strokeDashoffset: pathLength,
          }}
          animate={{
            strokeDashoffset: 0,
          }}
          transition={{
            duration: speed,
            ease: "easeInOut",
          }}
        >
          {text}
        </motion.text>

        <motion.text
          x="50%"
          y="50%"
          textAnchor="middle"
          dominantBaseline="middle"
          className={cn("text-7xl stroke-transparent", fontClassName)}
          style={{ fill: color }}
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{
            duration: 1,
            ease: "easeOut",
            delay: speed * 0.6, 
          }}
        >
          {text}
        </motion.text>
      </motion.svg>
    </div>
  );
}
How it Works

This component uses Framer Motion to animate the SVG stroke-dashoffset property.

  • First, it renders the text outline (stroke) and animates it from 0 to 100%.
  • Then, it fades in the fill color to make the text solid.
  • It uses next/font to support any Google Font.
Props
textRequired
string
The text to display.
fontClassName
string
Class from next/font.
speed
number
Duration in seconds. Default: 2
color
string
Stroke/Fill color. Default: currentColor
strokeWidth
number
Thickness of the line. Default: 1.5