Search Interaction
A small study of the moment between asking and finding.
About the interaction
A small study on what a search field should feel like while it works. The empty field comes alive with a soft, liquid orb and a quiet "Creating..." label, so the wait feels calm instead of frozen. Built with a few layers of gradients, blur and slow, looping motion.
Prompt
Paste this into your AI tool of choice to recreate the interaction.
Build a single, self-contained HTML file (HTML, CSS and a few lines of JavaScript, no libraries) that shows a search field "waking up" while it works. Layout - Centre everything on a light grey page (#e4e4e4). - The search field is a wide white pill: about 560px wide, 84px tall, fully rounded. Give it a very subtle top-to-bottom white gradient, a thin bright inner highlight along the top edge, and a soft, diffused drop shadow so it feels slightly raised. - Inside the field, on the left, there is a round orb (about 56px). To its right, a label that reads "Creating..." in a light cool grey (#a7adba), around 28px, regular weight. The orb - It should look like a small glossy sphere of liquid colour: a deep blue base (#2326c4) with soft swirls of magenta (#d2368c), blush pink (#f4a9c6) and a darker navy (#1a1470). - Build the swirls from three blurred colour blobs inside a circular mask, each rotating continuously at a different speed and direction (roughly 7s, 9s and 12s), so the colours slowly churn and never repeat in an obvious way. - Add an inner shadow at the bottom right and a small blurred white highlight at the top left so it reads as a 3D sphere. - Surround it with a soft pink glow ring that slightly spills past its edge. Motion - Start in an idle state: an empty field, no orb and no label. - After about 1.2 seconds, switch to a working state: the orb scales up from 40% to 100% with a gentle overshoot (spring-like easing) while fading in, and the label fades in and slides a few pixels from the left with a short delay after the orb. - Loop the whole sequence every 9 seconds so it can be watched again. - Respect prefers-reduced-motion by stopping the swirling. Keep the code clean and commented, with colours defined as CSS variables at the top.
Code
The same interaction as a single HTML file. Save it and open it in a browser.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Search Interaction</title>
<style>
:root {
--bg: #e4e4e4;
--field: #fbfbfb;
--label: #a7adba;
--blue: #2326c4;
--navy: #1a1470;
--pink: #d2368c;
--blush: #f4a9c6;
}
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: var(--bg);
font-family: "Inter", system-ui, sans-serif;
}
/* the search field: soft white pill with a light top edge */
.field {
width: min(560px, 90vw);
height: 84px;
padding: 0 18px;
display: flex;
align-items: center;
gap: 18px;
border-radius: 999px;
background: linear-gradient(180deg, #ffffff 0%, var(--field) 100%);
box-shadow:
inset 0 2px 0 rgba(255, 255, 255, 0.9),
0 18px 40px rgba(0, 0, 0, 0.08),
0 2px 6px rgba(0, 0, 0, 0.05);
}
/* the orb: a glowing ring around a slowly churning liquid sphere */
.orb {
position: relative;
flex: none;
width: 56px;
height: 56px;
border-radius: 50%;
opacity: 0;
transform: scale(0.4);
transition:
opacity 0.5s ease,
transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.orb::before {
content: "";
position: absolute;
inset: -9px;
border-radius: 50%;
background: radial-gradient(circle, rgba(244, 169, 198, 0.6) 58%, rgba(244, 169, 198, 0) 74%);
filter: blur(2px);
}
.liquid {
position: absolute;
inset: 0;
border-radius: 50%;
overflow: hidden;
background: var(--blue);
box-shadow: inset -6px -8px 14px rgba(20, 10, 80, 0.45), inset 5px 6px 10px rgba(255, 255, 255, 0.25);
}
/* three colour blobs drifting at different speeds create the "liquid" */
.liquid span {
position: absolute;
inset: -35%;
border-radius: 42%;
filter: blur(4px);
animation: churn 7s linear infinite;
}
.liquid span:nth-child(1) {
background: radial-gradient(ellipse 30% 22% at 32% 38%, var(--pink) 0 60%, transparent 100%);
}
.liquid span:nth-child(2) {
background: radial-gradient(ellipse 18% 26% at 66% 60%, var(--blush) 0 50%, transparent 100%);
animation-duration: 9s;
animation-direction: reverse;
}
.liquid span:nth-child(3) {
background: radial-gradient(ellipse 34% 20% at 55% 74%, var(--navy) 0 55%, transparent 100%);
animation-duration: 12s;
}
/* a small glossy highlight keeps it reading as a sphere */
.liquid::after {
content: "";
position: absolute;
top: 12%;
left: 18%;
width: 34%;
height: 22%;
border-radius: 50%;
background: rgba(255, 255, 255, 0.35);
filter: blur(3px);
}
.label {
font-size: 28px;
letter-spacing: -0.01em;
color: var(--label);
opacity: 0;
transform: translateX(-8px);
transition:
opacity 0.6s ease 0.25s,
transform 0.6s ease 0.25s;
}
.field.is-working .orb {
opacity: 1;
transform: scale(1);
}
.field.is-working .label {
opacity: 1;
transform: none;
}
@keyframes churn {
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.liquid span {
animation: none;
}
}
</style>
</head>
<body>
<div class="field" role="status" aria-live="polite">
<div class="orb" aria-hidden="true">
<div class="liquid"><span></span><span></span><span></span></div>
</div>
<span class="label">Creating...</span>
</div>
<script>
// idle -> working -> idle, on a loop: the field rests, then wakes up
const field = document.querySelector(".field");
const cycle = () => {
field.classList.remove("is-working");
setTimeout(() => field.classList.add("is-working"), 1200);
};
cycle();
setInterval(cycle, 9000);
</script>
</body>
</html>