Text✨ Premium

Scramble Text

A 30 ms setInterval replaces each character with a random symbol from a 42-glyph set, then reveals them left to right at one-third of a position per tick — a decoder effect triggered on hover.

JSDecoderMatrix

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Text has 56 effects, including 4 free. Explore the category →

3 usage examples

Dark landing page — Code name deciphering on hover — Scramble Text example 1

① Dark landing page — Code name deciphering on hover

WhenThe visitor lands on a cyberpunk or terminal-aesthetic landing page: the large headline reveals its identity on first hover.
WhyThe progressive decoder creates narrative tension — the name stays mysterious for a fraction of a second before it resolves, ideal for a tech brand or a high-identity product launch.
SettingsShort uppercase text (5–8 chars), font-size 3–5 rem, interval at 30 ms, iterations += 1/3 — reveal in ≈ 600 ms for 6 letters.
Terminal navigation menu — Links that scramble on hover — Scramble Text example 2

② Terminal navigation menu — Links that scramble on hover

WhenIn a dark UI (dashboard, pro tool, online IDE), horizontal or vertical nav items scramble when hovered.
WhyScrambling a short word (HOME, DOCS, API) takes under 300 ms — enough to perceive the animation without interrupting navigation. Strengthens the 'command-line' identity without slowing UX.
SettingsShort text (4–6 chars), interval at 30 ms, iterations += 1/2 (60 ms/char) for a crisper reveal; color matched to your nav palette.
Game interface — Player name or mission code revealed — Scramble Text example 3

③ Game interface — Player name or mission code revealed

WhenOn a debrief or results screen (FPS, strategy, quiz), the code name or team callsign decodes before the player's eyes.
WhyThe sequence of random symbols (0–9, @#$) instantly evokes hacker jargon and spy movies — meaningful in a game context without any explanation.
SettingsUppercase text (6–10 chars), interval at 40 ms for a slower, more dramatic decode, iterations += 1/4 (120 ms/char), triggered on DOMContentLoaded rather than hover.

How it works

On mouseenter, a setInterval fires every 30 ms. Each tick rebuilds the full text content: positions below iterations return the original character, positions above draw randomly from 42 symbols (A–Z, 0–9, @#$%&*). The result is assigned in one shot via textContent — no per-character DOM manipulation.

iterations advances by 1/3 per tick: each position stays scrambled for roughly three ticks (≈ 90 ms) before locking onto the correct character. Revelation moves strictly left to right — the eye reads a progressive decoder rather than random noise.

The interval stops as soon as iterations >= originalText.length (all characters revealed). On mouseleave, clearInterval cancels the current interval and textContent is restored instantly to its original value — no exit animation.

The target element uses "Courier New", monospace: fixed glyph width regardless of symbol, zero layout shift during replacement. The indigo color #6366f1 reinforces the terminal/system aesthetic.

Accessibility

  • prefers-reduced-motion: absent from the code — the effect fires even if the OS requests reduced motion. Add if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; at the top of the mouseenter handler to disable the scramble.
  • No keyboard trigger: the effect only listens on mouseenter/mouseleave — keyboard users never see the animation. Recommendation: mirror the same handlers on focus/blur.
  • Repeated textContent updates may be announced by some screen readers on every tick. Recommendation: add aria-hidden="true" to the scrambled element and include a <span class="sr-only"> with the static text outside the flow.
  • The original text is always readable before hover and is restored instantly on mouseleave — no locked state.
  • The monospace font keeps the line width stable during scramble: no layout reflow, no shift of adjacent content.

Browser compatibility

Requires setInterval and textContent — supported in every browser since 2010. Zero external dependencies.

Chrome 100+✓ Full
Firefox 100+✓ Full
Safari 15+✓ Full
Edge 100+✓ Full
Mobile iOS✓ No native hover — trigger via touchstart
Android Chrome✓ Same as iOS — tap required

Without JS, the text stays static, styled in indigo monospace — consistent render, no fatal error.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="demo-preview">
  <span class="demo-text splitting-text-scramble" id="scrambleTextHover">YOUR TEXT</span>
  <!-- Optional: Replay button -->
  <button class="replay-btn" onclick="replayScramble()">Replay</button>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
chars (JS, line 7) 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%&*' 42-symbol replacement set. Narrow to 'ABCDEF0123456789' for a hex look, or '!@#$%^&*' for a more aggressive tone.
setInterval (JS, line 14) 30 Delay in ms between ticks. 20 ms = ultra-fast decoder; 60 ms = slow, dramatic deciphering.
iterations += (JS, line 22) 1/3 Reveal step per tick. 1/3 → 3 ticks/char (~90 ms/char); 1/2 → ~60 ms/char (snappy); 1/6 → ~180 ms/char (slow).
color (.splitting-text-scramble) #6366f1 Text color for both the scrambled and final states. Swap in your brand color.
font-family (.splitting-text-scramble) "Courier New", monospace Monospace is required to prevent width jumps. Swap to 'JetBrains Mono', 'Fira Code', or any installed monospace face.
font-size (.demo-text) 2.5rem Text size. The larger the text, the more visible the scramble — scale to your typographic hierarchy.

FAQ

The JS targets getElementById('scrambleTextHover'). If your span has a different id (e.g. id="scrambleText"), either add id="scrambleTextHover" to your element or update the getElementById line to match your actual id.
Replace the mouseenter listener with a direct call after initialization: remove the addEventListener('mouseenter', ...) block and place its body (the setInterval) directly inside the IIFE, after scrambleInterval is declared. The Replay button can then re-trigger it via scrambleEl.dispatchEvent(new Event('mouseenter')).
The JS hardcodes a single id. For multiple targets, replace getElementById with querySelectorAll('.splitting-text-scramble') and initialize each element in a loop — each needs its own scrambleInterval and its own originalText copy.