Search Input With Icon

A premium search input with a focused state and an icon that becomes a submit action as you type.

Add to your project

Pick the way you like to build.

Let your AI assistant add it

Copy this prompt and paste it into the AI tool building your site.

# Integrate this UI component

Add this component to my project.

1. Install any missing dependencies.
2. Make sure Tailwind CSS is set up and scans the new file.
3. Prefer passing props over editing the component source — changing the component itself may break it.
4. Adjust colors, size, and layout via props or wrapper classes to match my project. You know my codebase better than this snippet does.

## Component source

```tsx
"use client";

import { useState } from "react";
import type { FormEvent, InputHTMLAttributes } from "react";
import { ArrowRight, Search } from "lucide-react";

type SearchInputWithIconProps = Omit<
  InputHTMLAttributes<HTMLInputElement>,
  "type"
> & {
  // eslint-disable-next-line no-unused-vars
  onSearch?: (query: string) => void;
  className?: string;
};

export default function SearchInputWithIcon({
  value,
  defaultValue = "",
  onChange,
  onSearch,
  "aria-label": ariaLabel,
  className = "",
  disabled,
  ...props
}: SearchInputWithIconProps) {
  const [query, setQuery] = useState(String(value ?? defaultValue));
  const displayValue = value === undefined ? query : String(value);
  const hasQuery = displayValue.length > 0;

  const submit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (displayValue.trim()) onSearch?.(displayValue);
  };

  return (
    <form
      onSubmit={submit}
      className={[
        "group flex h-12 w-full items-center rounded-xl border border-gray-200 bg-white p-1 shadow-sm transition-all duration-200 focus-within:border-gray-400 focus-within:shadow-md",
        disabled && "opacity-60",
        className,
      ]
        .filter(Boolean)
        .join(" ")}
    >
      <input
        {...props}
        type="search"
        aria-label={ariaLabel ?? "Search"}
        value={displayValue}
        disabled={disabled}
        onChange={(event) => {
          setQuery(event.target.value);
          onChange?.(event);
        }}
        className="min-w-0 flex-1 bg-transparent px-3 text-sm text-gray-950 outline-none placeholder:text-gray-400 [&::-webkit-search-cancel-button]:hidden"
      />
      <button
        type="submit"
        aria-label={hasQuery ? "Submit search" : "Search"}
        disabled={disabled || !hasQuery}
        className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg text-gray-400 transition-all duration-200 group-focus-within:bg-gray-950 group-focus-within:text-white disabled:group-focus-within:bg-transparent disabled:group-focus-within:text-gray-400 disabled:cursor-default"
      >
        {hasQuery ? (
          <ArrowRight className="h-4 w-4" aria-hidden="true" />
        ) : (
          <Search
            className="h-4 w-4 transition-transform duration-200 group-focus-within:scale-90"
            aria-hidden="true"
          />
        )}
      </button>
    </form>
  );
}

```

Works with your AI tools

ClaudeClaude*
CodexCodex*
LovableLovable
Base44Base44
Figma MakeFigma Make
ReplitReplit*
CursorCursor*
v0v0

* Compatible with most projects that use the default React/Next.js framework.

Built With

ReactTailwind CSSLucide

Props

PropTypeDescription
onSearch(query: string) => voidCalled when the form is submitted with a search query
valuestringControlled search query
defaultValuestringInitial query when uncontrolled
placeholderstringText shown before a query is entered
disabledbooleanDisables the input and submit action
classNamestringStyles for the outer form

More Input Components

A minimalist input spinner for choosing quantities with buttons, typing, or arrow keys.