
The menu that opens from its button
Menus, Transitions, Text
Free
In the minimal style: the search of a personal journal that finishes the word as you type. The rest of the topic waits after the caret, in the same face but thin and narrow, and every letter typed over it inks in, taking weight and width on a spring. The field’s line closes in under the word written and a dotted line measures what is left; Tab completes it, the arrows choose another topic and the end of the word rolls to the new one.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The search that finishes the word</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/full.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the search of a personal journal. Typing, the field finishes the word: the rest of the best topic waits
after the caret in hairline, condensed letters, and every letter typed over it inks in. The thin line of the
field closes in under the word written, and a dotted line measures what is left to write. Tab, the right
arrow or a tap on the grey letters complete it; the arrows choose another topic; Enter searches.
The letters and the rows are made by the script from the list at the top of script.js -->
<div class="finish" data-finish data-autoclic>
<div class="finish__field" data-field>
<svg class="finish__lens" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.5 4.75a5.75 5.75 0 1 0 0 11.5a5.75 5.75 0 1 0 0-11.5zM14.75 14.75l4.75 4.75"/></svg>
<div class="finish__wrap" data-wrap>
<div class="finish__shake" data-shake>
<span class="finish__holder" aria-hidden="true" data-holder>Search the journal</span>
<div class="finish__track" aria-hidden="true" data-track>
<span class="finish__text" data-text></span>
<span class="finish__caret" data-caret></span>
</div>
</div>
<input class="finish__input" id="finish-input" type="text" inputmode="search" enterkeyhint="search" role="combobox" aria-label="Search the journal" aria-autocomplete="both" aria-expanded="false" aria-controls="finish-list" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" maxlength="20" data-input>
</div>
<button class="finish__key" type="button" tabindex="-1" aria-label="Complete the word" data-key>
<span class="key__tab" aria-hidden="true">tab</span>
<svg class="key__arrow" viewBox="0 0 20 20" aria-hidden="true"><path d="M4 10h11.5M11 5.5l4.5 4.5L11 14.5"/></svg>
</button>
<span class="finish__rule" aria-hidden="true">
<span class="rule__ink" data-ink></span>
<span class="rule__dots" data-dots></span>
<span class="rule__tick" data-tick></span>
</span>
</div>
<div class="finish__room" data-room>
<span class="finish__band" aria-hidden="true" data-band></span>
<ul class="finish__list" id="finish-list" role="listbox" aria-label="Topics" data-list></ul>
<p class="finish__note" data-note></p>
</div>
<p class="sr" role="status" aria-live="polite" data-said></p>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.
85 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The search that finishes the word” from Animorio and fit it into my siteThe input is there and real, with role combobox, aria-autocomplete both, aria-expanded and aria-activedescendant, but its text and its caret are transparent: it keeps the keyboard, the selection, pasting and screen readers. The letters you see are spans drawn by the script, one per character and with kerning off, in the same face and size as the input, so a click lands in the right place. The caret is a blue segment placed after the right letter, measured with getBoundingClientRect.
At every change syncLetters() lines up the letters typed and then the ending of the topic chosen, and compares them with the spans already there: as long as the character is the same (ignoring case) the span stays and only changes state, inked or grey. The rest leaves: those spans are taken out of the line where they stand, set in absolute position at the same spot and made to drop and fade, so the letters left close up at once. The new ones open from a sliver, from the wdth axis at 25 to the grey one’s width.
Roboto Flex has the wght axis from 100 to 1000 and wdth from 25 to 151: the letters still to write sit at GHOST (weight 130, width 70), the written ones at INKED (470 and 100). GSAP carries both axes on a damped spring curve written as a function, which passes the goal by a few units and comes back, and rewrites font-variation-settings on every frame. The colour goes from grey to black with a CSS transition, delayed like the weight when the word is completed as a wave, one letter every STAGGER seconds.
The blue line has two ends and the dotted line a third, each on a real spring (the stiffness and damping of SPRING, the step capped at 1/30 of a second and split into steps of 1/240). On every frame the loop measures where the last letter typed and the last grey one end, even halfway through their animation, and the springs follow them: so the line closes in from the full width to under the first letter and then grows letter by letter. The loop stays on only while something moves, and wakes again on resize because the measures are in pixels.
search() keeps the topics starting with the letters typed, the most read first; the topic chosen stays the same as long as it matches, so deleting does not change it under your fingers. The rows are positioned absolutely: the ones no longer valid fade in 0.12 seconds, the others wait and slide to their new place with a small overshoot, the new ones come up one after another. The arrows or the pointer move the band and roll the ending in the field; Tab and the right arrow complete it only when there is one, otherwise Tab does its usual job.
A click from a script (detail 0, the library’s preview) starts a GSAP timeline of about 9 seconds that types without taking the focus: p, then o (the ending goes from Photography to Poetry), the down arrow onto Pottery, t over the grey t, Tab, Enter, and finally Escape brings everything back to rest. While the tour runs other clicks from a script are ignored; a real touch or key stops it at once.
| Name | File | Default | What it changes |
|---|---|---|---|
TOPICS | script.js | [['Photography', 14], ['Poetry', 11], ['Pottery', 9], …] | The journal’s topics, and how many essays each one has. |
SHOWN | script.js | 5 | How many topics the list shows at most. |
UNIT | script.js | ['essay', 'essays'] | The word after the count, for one and for more. |
GHOST | script.js | [130, 70] | The weight and the width of the letters still to write. |
INKED | script.js | [470, 100] | The weight and the width of the letters written. |
STAGGER | script.js | 0.04 | The seconds between one letter and the next inking in when the word is completed. |
SETTLE | script.js | 0.55 | The seconds a letter takes to ink in and settle. |
SPRING | script.js | [420, 35] | The spring of the line under the word: stiffness and damping. |
TRIES | script.js | ['Photography', 'Bread', 'Walking'] | The topics offered when nothing is typed. |
For the search of a blog, a journal, a product’s documentation, a shop with short category names or the tag field of an app: wherever the words to search for are few and known and it helps to finish them for whoever types, as the browser’s address bar does. The search() function is the only one to change to ask a server for the topics.
The field takes the width of the screen minus 32 pixels and the words drop to 27 pixels, so even Photography fits easily; the field tells the keyboard to show the search key. A phone has no Tab key: in its place, to the right of the field, there is a circle with a drawn arrow, and a tap on the grey letters also completes the word. The rows stay 46 pixels tall for the finger and a tap picks one and searches it. Axes, springs and rolls are the same as on a computer.
No springs, drops or rolls: the blue line jumps straight under the word, the grey ending fades in and out already in place, the list’s rows appear and fade without moving and the band jumps from row to row. The letters ink in, changing weight and width in a fifth of a second, with no wave and no overshoot, and the field neither jolts nor shakes its head.
GSAP 3.15.0, Roboto Flex (font variabile, assi wght e wdth) 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 18 October 2026
Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.