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

Sizes

Small

Default (450px)

Large

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

PropertyDefaultDescription
--art-gemini-input-width450pxOverall container width
--art-gemini-input-border-size4pxBorder thickness and inset depth of the border overlay
--art-gemini-input-gradientconic rainbowThe full animated conic-gradient definition
--art-gemini-input-rotation0degAnimated angle driving gradient rotation (registered via @property)

API Reference

ClassDescription
.art-gemini-inputRoot container β€” sets width, border, animation, and gradient tokens
.art-gemini-input-smSize modifier β€” sets width to 280px
.art-gemini-input-lgSize modifier β€” sets width to 640px
.art-gemini-input-innerInner pill β€” white/dark background, grid layout with bottom-aligned buttons
.art-gemini-input-borderAnimated border overlay β€” masked to show only the border strip
.art-gemini-input-btnAction button β€” transparent background, bottom-aligned in the grid
.art-gemini-input-fieldTextarea β€” auto-grows via field-sizing: content (Chrome 123+, Firefox 130+), capped at 8rem