Gemini Input
Animated AI-style multiline input with a rotating rainbow conic-gradient border and soft glowing backdrop
Gemini Input
An animated multiline input styled after Googleβs Gemini AI interface. It uses a rotating conic-gradient driven by a Houdini @property custom property (--art-gemini-input-rotation) to smoothly spin the rainbow border. A mask: linear-gradient(white) on the .art-gemini-input-border overlay clips the gradient precisely to the border area, while a filter: blur copy behind the container creates the soft glowing halo effect. The <textarea> uses field-sizing: content for pure-CSS auto-grow β no JavaScript required.
Ported from a CodePen by animmaster_studio.
Basic Usage
Gemini Input
<div class="art-gemini-input">
<div class="art-gemini-input-inner">
<button class="art-gemini-input-btn" aria-label="Add">+</button>
<textarea class="art-gemini-input-field" placeholder="Ask Gemini" rows="1"></textarea>
<button class="art-gemini-input-btn" aria-label="Microphone">π€</button>
</div>
<div class="art-gemini-input-border"></div>
</div>Sizes
Small
<div class="art-gemini-input art-gemini-input-sm">
<div class="art-gemini-input-inner">
<button class="art-gemini-input-btn" aria-label="Add">+</button>
<textarea class="art-gemini-input-field" placeholder="Ask Gemini" rows="1"></textarea>
<button class="art-gemini-input-btn" aria-label="Microphone">π€</button>
</div>
<div class="art-gemini-input-border"></div>
</div>Default (450px)
<div class="art-gemini-input">
<div class="art-gemini-input-inner">
<button class="art-gemini-input-btn" aria-label="Add">+</button>
<textarea class="art-gemini-input-field" placeholder="Ask Gemini" rows="1"></textarea>
<button class="art-gemini-input-btn" aria-label="Microphone">π€</button>
</div>
<div class="art-gemini-input-border"></div>
</div>Large
<div class="art-gemini-input art-gemini-input-lg">
<div class="art-gemini-input-inner">
<button class="art-gemini-input-btn" aria-label="Add">+</button>
<textarea class="art-gemini-input-field" placeholder="Ask Gemini" rows="1"></textarea>
<button class="art-gemini-input-btn" aria-label="Microphone">π€</button>
</div>
<div class="art-gemini-input-border"></div>
</div>CSS
@property --art-gemini-input-rotation {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@layer css-art {
@keyframes art-gemini-input-rotate {
to {
--art-gemini-input-rotation: 360deg;
}
}
.art-gemini-input {
--art-gemini-input-width: 450px;
--art-gemini-input-border-size: 4px;
--art-gemini-input-gradient: conic-gradient(
from var(--art-gemini-input-rotation) at 52% 49% in oklab,
oklch(0.63 0.2 251.22) 27%,
oklch(0.67 0.21 25.81) 33%,
oklch(0.9 0.19 93.93) 41%,
oklch(0.79 0.25 150.49) 49%,
oklch(0.63 0.2 251.22) 65%,
oklch(0.72 0.21 150.89) 93%,
oklch(0.63 0.2 251.22)
);
color-scheme: light dark;
position: relative;
width: var(--art-gemini-input-width);
animation: art-gemini-input-rotate 5s infinite linear;
border-radius: 4rem;
background: none;
padding: 0;
border: var(--art-gemini-input-border-size) solid lightgray;
/* Glow halo β z-index: 1 sits below the border (z-index 2) and inner
content (z-index 3). z-index: -1 is invisible inside GPU-composited
stacking contexts (created by animation), so z-index: 1 is required. */
&::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
background: var(--art-gemini-input-gradient);
top: 50%;
left: 50%;
translate: -50% -50%;
z-index: 1;
animation: art-gemini-input-rotate 5s infinite linear;
filter: blur(15px);
}
& .art-gemini-input-inner {
background: light-dark(white, #1a1c1e);
color: light-dark(#222, hsl(210, 8%, 66%));
padding: 0.75rem 0.5rem;
position: relative;
z-index: 3;
border-radius: inherit;
display: grid;
grid-template-columns: auto 1fr auto;
align-items: end;
gap: 0.75rem;
}
& .art-gemini-input-border {
position: absolute;
inset: calc(var(--art-gemini-input-border-size) * -1);
mask: linear-gradient(white);
border-radius: inherit;
overflow: hidden;
z-index: 2;
&::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: var(--art-gemini-input-gradient);
top: 50%;
left: 50%;
translate: -50% -50%;
animation: art-gemini-input-rotate 5s infinite linear;
filter: blur(5px);
}
}
& .art-gemini-input-btn {
color: light-dark(#222, hsl(210, 8%, 66%));
background: none;
border: none;
cursor: pointer;
padding: 0;
line-height: 1;
font-size: 1.25rem;
display: inline-flex;
align-items: center;
justify-content: center;
user-select: none;
}
& .art-gemini-input-field {
color: light-dark(#222, hsl(210, 8%, 66%));
background: none;
border: none;
cursor: text;
font-size: 1rem;
font-family: system-ui;
font-weight: 300;
line-height: 1.5;
width: 100%;
resize: none;
field-sizing: content;
min-height: 1.5em;
max-height: 8rem;
overflow-y: auto;
&:focus,
&:focus-visible {
outline: none !important;
}
&:not(:placeholder-shown) {
color: light-dark(black, white);
}
}
}
.art-gemini-input-sm { --art-gemini-input-width: 280px; }
.art-gemini-input-lg { --art-gemini-input-width: 640px; }
}
HTML Structure
<div class="art-gemini-input">
<div class="art-gemini-input-inner">
<button class="art-gemini-input-btn" aria-label="Add">+</button>
<textarea class="art-gemini-input-field" placeholder="Ask Gemini" rows="1"></textarea>
<button class="art-gemini-input-btn" aria-label="Microphone">π€</button>
</div>
<div class="art-gemini-input-border"></div>
</div>
The .art-gemini-input-border div is required β it holds the ::after pseudo-element that renders the animated conic-gradient border via mask. Use <textarea> (not <input>) to enable multiline auto-grow via field-sizing: content. The rows="1" attribute sets the single-line initial height.
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--art-gemini-input-width | 450px | Overall container width |
--art-gemini-input-border-size | 4px | Border thickness and inset depth of the border overlay |
--art-gemini-input-gradient | conic rainbow | The full animated conic-gradient definition |
--art-gemini-input-rotation | 0deg | Animated angle driving gradient rotation (registered via @property) |
API Reference
| Class | Description |
|---|---|
.art-gemini-input | Root container β sets width, border, animation, and gradient tokens |
.art-gemini-input-sm | Size modifier β sets width to 280px |
.art-gemini-input-lg | Size modifier β sets width to 640px |
.art-gemini-input-inner | Inner pill β white/dark background, grid layout with bottom-aligned buttons |
.art-gemini-input-border | Animated border overlay β masked to show only the border strip |
.art-gemini-input-btn | Action button β transparent background, bottom-aligned in the grid |
.art-gemini-input-field | Textarea β auto-grows via field-sizing: content (Chrome 123+, Firefox 130+), capped at 8rem |