slot-text

repository·main·Indexed 21 days ago

https://github.com/danilaa1/slot-text

A dependency-free library for creating tactile text roll animations for UI labels. It supports vanilla JavaScript and provides integrations for React, Vue, Solid, and Svelte. Key features include a SlotTextController for managing transitions via set() and flash() methods, customizable animation options (direction, stagger, duration, bounce), and a chromatic() helper for rainbow color effects.

Tokens
6.1K
Snippets
25
Records
28
Agent score
75%

What's inside slot-text

  1. Understand font and rendering limitations

    main

    The animation works by measuring each character in its own cell using the element's exact font. While highly compatible with most fonts, be aware of the following:

    • Kerning: Pair kerning (e.g., AV) is lost as characters are isolated.
    • Ligatures: Ligatures (e.g., fi, fl) will not form.
    • Joined Scripts: Scripts like Arabic or Devanagari may render as isolated forms.
    • Grapheme Clusters: Uses Intl.Segmenter where available; otherwise falls back to Unicode code points.
    • Clipping: Very tall display fonts might clip at the roll mask (recommended line-height: 1.3).
  2. Install slot-text

    main

    Install slot-text using your preferred package manager. This is a dependency-free library for text roll animations.

    # npm
    npm install slot-text
    
    # pnpm
    pnpm add slot-text
    
    # Bun
    bun add slot-text
    
    # Yarn
    yarn add slot-text
  3. Quick start with vanilla JavaScript

    main

    To use slot-text in a vanilla environment, import the required CSS once, then use the slotText function to attach the animation to a DOM element. You can use chromatic() to apply a rainbow color effect.

    import "slot-text/style.css";
    import { slotText, chromatic } from "slot-text";
    
    const label = slotText(document.querySelector("#copy")!, "Copy");
    
    // the classic Copy → Copied → Copy, in one call
    label.flash("Copied", { enter: { color: chromatic() } });
  4. Configure slot-text animation options

    main

    You can customize the animation behavior using an options object. Supported keys include:

    OptionDefaultDescription
    direction"down"Roll direction: "up" or "down"
    stagger45Delay between characters (ms)
    duration300Per-character animation time (ms)
    exitOffset50Delay before the old character exits (ms)
    easingspringy bezierCSS easing function
    bounce0.6Overshoot amount
    colorColor string, or (index, total) => string
    colorFade280Fade back to base color (ms)
    skipUnchangedtrueDon't re-roll identical characters
    interrupttrueControls how new calls affect in-flight animations

    Note on interrupt:

    • interrupt: true (default): Cuts off any roll in flight and starts the new one immediately.
    • interrupt: false: Lets the current roll finish; the latest call plays after the current one lands. This is useful for preventing animation jitter on spam-prone buttons.
  5. Integrate with Svelte

    main

    Use the slotText action from slot-text/svelte. Ensure you import slot-text/style.css in your project.

    <script lang="ts">
      import "slot-text/style.css";
      import { slotText } from "slot-text/svelte";
    
      let label = "Copy";
    </script>
    
    <button aria-label={label} on:click={() => label = "Copied"}>
      <span use:slotText={{ text: label, options: { direction: "up" } }}></span>
    </button>
  6. Use chromatic() for rainbow colors

    main

    The chromatic() helper is a built-in utility that can be passed to the color option to create a per-character hue sweep (rainbow effect).

    import { chromatic } from "slot-text";
    
    // Used in options
    label.flash("Copied", { enter: { color: chromatic() } });
  7. Integrate with React

    main

    Use the SlotText component from slot-text/react. Ensure you import slot-text/style.css in your project.

    import "slot-text/style.css";
    import { SlotText } from "slot-text/react";
    import { chromatic } from "slot-text";
    
    <SlotText
      text={copied ? "Copied" : "Copy"}
      options={{ direction: copied ? "up" : "down", color: copied ? chromatic() : undefined }}
    />
  8. Integrate with Solid

    main

    Use the slotText directive from slot-text/solid. Ensure you import slot-text/style.css in your project.

    import "slot-text/style.css";
    import { createSignal } from "solid-js";
    import { slotText } from "slot-text/solid";
    
    const [label, setLabel] = createSignal("Copy");
    
    <button aria-label={label()} onClick={() => setLabel("Copied")}>
      <span use:slotText={{ text: label(), options: { direction: "up" } }} />
    </button>
  9. Integrate with Vue

    main

    Use the SlotText component from slot-text/vue. Ensure you import slot-text/style.css in your project.

    <script setup lang="ts">
    import "slot-text/style.css";
    import { SlotText } from "slot-text/vue";
    </script>
    
    <template>
      <SlotText text="Copied" :options="{ direction: 'up' }" />
    </template>
  10. Use the slotText API methods

    main

    The slotText function returns an object with the following methods to control the animation:

    • set(text, options?): Rolls to the new text and keeps it permanently.
    • flash(text, options?): Rolls in the new text, then automatically reverts to the previous text after a specified duration. This method is spam-safe; repeat calls restart the revert timer.
    • destroy(): Cleans up the animation and associated resources.
    const label = slotText(element, "Copy", options);
    
    label.set("Copied");                  // permanent change
    label.set("Copy", { direction: "down" });
    label.flash("Copied");                // temporary — rolls back after 1.4s
    label.destroy();
    
    // Advanced flash configuration
    label.flash("Copied", {
      revertAfter: 1400,                              // ms before rolling back
      enter: { direction: "up", color: chromatic() }, // roll-in
      exit: { direction: "down" },                    // roll-back
    });
  11. Initialize a text-roll controller with slotText()

    main

    Use slotText() to create a SlotTextController for a specific HTML element. This controller manages text transitions (rolling/flashing) for that element.

    Note: You must import slot-text/style.css once in your application for the animations to work correctly.

    Parameters:

    • element: The HTMLElement to be controlled.
    • initialText: The starting text string.
    • defaultOptions (optional): A SlotOptions object to apply to all subsequent transitions.
    import { slotText } from 'slot-text';
    import 'slot-text/style.css';
    
    const buttonLabel = document.querySelector('#label') as HTMLElement;
    const label = slotText(buttonLabel, "Copy");
    
    // Transition to new text
    label.set("Copied", { direction: "up" });
    
    // Show temporary text that automatically reverts
    label.flash("Copied", { revertAfter: 1400 });
  12. Use SlotText in Vue

    main

    The SlotText component is a Vue wrapper for the slot-text library. It renders text into a <span> element and handles text animations and CSS fallbacks automatically.

    Props

    • text (String, Required): The text content to be displayed and animated.
    • options (Object, Optional): An object of type SlotOptions to configure the animation behavior.

    Behavior

    • Initial Render: On mount, the component uses renderTextWithCssFallback to display the initial text.
    • Updates: When the text prop changes, the component triggers animateSlotText to transition to the new text.
    • Cleanup: On unmount, the component calls clearSlotText to clean up the DOM.
    • Accessibility: It renders a <span> and automatically sets an aria-label to the current text value unless an aria-label is explicitly provided via attributes.
    <script setup>
    import { SlotText } from 'slot-text/vue'; // Adjust import path based on your installation
    
    const myText = ref('Hello World');
    </script>
    
    <template>
      <SlotText 
        :text="myText" 
        :options="{ interrupt: true }" 
        class="my-custom-class"
      />
    </template>