Torph: Animated Text Morphing for Vanilla JS, React, Vue, and More

Category: Animation , Javascript , Recommended , Text | June 15, 2026
Authorlochie
Last UpdateJune 15, 2026
LicenseMIT
Views0 views
Torph: Animated Text Morphing for Vanilla JS, React, Vue, and More

Torph is a lightweight text animation library that morphs one text string into another using smooth, physics-based motion.

It uses the browser’s Intl.Segmenter to split text into words or graphemes, animates exiting segments with translation, opacity, and scale, and provides spring easing for natural-looking motion.

Features:

  • Morph changing text strings.
  • Support React, Vue, Svelte, and vanilla JavaScript.
  • Animate words or characters.
  • Add spring-style motion.
  • Handle locale-aware text segmentation.
  • Respect reduced-motion preferences.
  • Disable animation when needed.
  • Attach lifecycle callbacks.
  • Render custom HTML elements.
  • Custom classes and inline styles.

How To Use It:

Installation

Install the Torph package for JavaScript, React, Vue, and Svelte projects.

# Yarn
$ yarn add torph

# NPM
$ npm install torph

# PNPM
$ pnpm install torph

Vanilla JavaScript

The vanilla JavaScript API works well when you need one animated text node in a non-framework page or a custom widget. Create the target element first, then call update() when the displayed text changes.

<div id="product-status"></div>
import { TextMorph } from "torph";
// Create a morph instance for an existing DOM element.
const statusMorph = new TextMorph({
  element: document.getElementById("product-status"),
  duration: 350,
  ease: "cubic-bezier(0.19, 1, 0.22, 1)",
  locale: "en",
});
// Replace the text and run the morph animation.
statusMorph.update("Sync Complete");

React Implementation

The component accepts the text as children and renders the selected HTML element through as.

import { useState } from "react";
import { TextMorph } from "torph/react";
export default function BillingHeader() {
  const [planName, setPlanName] = useState("Starter Plan");
  return (
    <>
      <TextMorph
        as="h2"
        duration={420}
        ease="cubic-bezier(0.19, 1, 0.22, 1)"
        locale="en"
        className="billing-heading"
        onAnimationComplete={() => console.log("Plan label updated")}
      >
        {planName}
      </TextMorph>
      <button onClick={() => setPlanName("Business Plan")}>
        Change Plan
      </button>
    </>
  );
}

The hook returns a ref and an update function for lower-level component composition.

import { useEffect } from "react";
import { useTextMorph } from "torph/react";
type StatusBadgeProps = {
  statusText: string;
};
export function StatusBadge({ statusText }: StatusBadgeProps) {
  const { ref, update } = useTextMorph({
    duration: 300,
    ease: "cubic-bezier(0.19, 1, 0.22, 1)",
  });
  useEffect(() => {
    // Send new text to the morph controller.
    update(statusText);
  }, [statusText, update]);
  return <span ref={ref} className="status-badge" />;
}

Vue Implementation

A Vue component can pass reactive text into the Torph component. Keep the text value as a string and update the ref when the UI state changes.

<script setup>
import { ref } from "vue";
import { TextMorph } from "torph/vue";
const checkoutStep = ref("Shipping Details");
function goToPayment() {
  checkoutStep.value = "Payment Method";
}
</script>
<template>
  <TextMorph
-text="checkoutStep"
-duration="400"
    ease="cubic-bezier(0.19, 1, 0.22, 1)"
    locale="en"
    class="checkout-step-title"
    as="h3"
  />
  <button @click="goToPayment">Next Step</button>
</template>

Svelte Implementation

A Svelte view can pass state into the Torph component. This works for Svelte 5 state syntax and keeps the morph target inside the component template.

<script>
  import { TextMorph } from "torph/svelte";
  let campaignLabel = $state("Draft Campaign");
  function publishCampaign() {
    campaignLabel = "Published Campaign";
  }
</script>
<TextMorph
  text={campaignLabel}
  duration={380}
  ease="cubic-bezier(0.19, 1, 0.22, 1)"
  locale="en"
  class="campaign-title"
  as="h2"
/>
<button on:click={publishCampaign}>Publish</button>

Spring motion

Spring motion is great for UI text that should feel less linear than a fixed CSS easing curve. Pass spring parameters to the easing option and Torph computes the animation duration from the spring values.

import { useState } from "react";
import { TextMorph } from "torph/react";
export function MetricLabel() {
  const [metricName, setMetricName] = useState("Monthly Revenue");
  return (
    <TextMorph
      as="strong"
      ease={{
        stiffness: 180,
        damping: 18,
        mass: 1,
        precision: 0.001,
      }}
    >
      {metricName}
    </TextMorph>
  );
}

Configuration Options

  • text / children (string): Sets the text content to display. Framework components use the format that matches the framework.
  • duration (number): Sets the animation duration in milliseconds. The default value is 400.
  • ease (string | SpringParams): Sets a CSS easing function or spring motion settings. The default value is "cubic-bezier(0.19, 1, 0.22, 1)".
  • scale (boolean): Adds scale animation to exiting text segments. The default value is true.
  • locale (Intl.LocalesArgument): Sets the locale for text segmentation. The default value is "en".
  • debug (boolean): Adds visual debug indicators around the root and text items.
  • disabled (boolean): Turns off morphing animations and updates the text directly. The default value is false.
  • respectReducedMotion (boolean): Checks the user’s reduced-motion preference and disables animation when reduction is requested. The default value is true.
  • onAnimationStart (() => void): Runs when an animation starts after the first render.
  • onAnimationComplete (() => void): Runs when the size transition and morph animation complete.
  • className (string): Adds a CSS class in React. Use class in Vue and Svelte templates.
  • style (object | string): Adds inline styles through the supported framework or DOM setup.
  • as (string): Sets the rendered HTML element. The default value is "span".

Spring Parameters

  • stiffness (number): Sets the spring stiffness coefficient. The default value is 100.
  • damping (number): Sets the damping coefficient. The default value is 10.
  • mass (number): Sets the spring mass. The default value is 1.
  • precision (number): Sets the threshold used to determine the settled position. The default value is 0.001.

API Methods

import { TextMorph, MorphController } from "torph";
// Create a vanilla JavaScript morph instance.
const headingMorph = new TextMorph({
  element: document.getElementById("release-heading"),
  duration: 400,
  ease: "cubic-bezier(0.19, 1, 0.22, 1)",
});
// Replace the current text and run the morph animation.
headingMorph.update("Version 2.4 Released");
// Stop active animations and clean up the instance.
headingMorph.destroy();
// Create a lower-level controller for custom integrations.
const controller = new MorphController();
// Attach the controller to an element with Torph options.
controller.attach(document.getElementById("account-label"), {
  duration: 320,
  locale: "en",
});
// Update the controlled text node.
controller.update("Account Verified");
// Check whether a new option set requires a recreated instance.
const shouldRecreate = controller.needsRecreate({
  duration: 500,
  locale: "en",
  scale: true,
  debug: false,
  disabled: false,
  respectReducedMotion: true,
  ease: "cubic-bezier(0.19, 1, 0.22, 1)",
});
// Destroy the controller and its internal morph instance.
controller.destroy();

Alternatives:

You Might Be Interested In:


Leave a Reply