Input
A form control for collecting user text input with support for various types, addons and icons.
Overview
The Input component is a flexible form control for collecting user text input. It supports various input types, decorative elements like addons and icons, multiple sizes, and URL state synchronization for preserving input values across page navigation.
Usage
import {
Input,
InputAddon,
InputGroup,
InputWrapper,
} from "@tilt-legal/cubitt-components/primitives";<Input type="email" placeholder="Email" />Using Cubitt's URL-state hooks, you can sync the input value with the URL by providing a paramName:
// Value syncs with ?search=... in URL
<Input
type="text"
placeholder="Search"
paramName="search"
/>
// Advanced options:
<Input
type="text"
placeholder="Filter"
paramName="filter"
paramClearOnDefault={true} // Remove param when empty
paramDebounce={300} // Debounce URL updates
onUrlValueChange={(value) => console.log('Filter:', value)}
/>Examples
Looking for date or time inputs? See the Date Input docs for DateInput,
DateInputRoot, and TimeInputRoot.
Basic Input
A simple text input field.
import { Input } from "@tilt-legal/cubitt-components/primitives";
<Input type="email" placeholder="Email" />;Disabled and Readonly
Input fields that are disabled or readonly.
import { Input } from "@tilt-legal/cubitt-components/primitives";
<Input type="text" placeholder="Disabled" disabled />
<Input
type="text"
placeholder="Readonly"
readOnly={true}
value="Readonly input"
/>With Addons
Use InputGroup with InputAddon to attach elements to an input. Each element maintains its own visual boundary.
import {
Button,
Input,
InputAddon,
InputGroup,
} from "@tilt-legal/cubitt-components/primitives";
import { Input, InputWrapper } from "@tilt-legal/cubitt-components/primitives";
import {
CurrencyEuro } from "@tilt-legal/cubitt-icons/ui/outline";
<InputGroup>
<InputAddon>Text</InputAddon>
<Input type="text" placeholder="Text addon" />
</InputGroup>
<InputGroup>
<InputAddon>
<CurrencyEuro />
</InputAddon>
<Input type="text" placeholder="Icon addon" />
</InputGroup>
<InputGroup>
<Input type="text" placeholder="Button addon" />
<Button variant="secondary" className="rounded-s-none rounded-e-xl">
Submit
</Button>
</InputGroup>With Embedded Elements
Use InputWrapper to place elements inside an input. Elements appear embedded within a single field.
import { Button } from "@tilt-legal/cubitt-components/primitives";
import {
CurrencyEuro,
Xmark } from "@tilt-legal/cubitt-icons/ui/outline";
<InputWrapper>
<Input type="text" placeholder="Text" />
<span className="text-fg-3">@tilt.legal</span>
</InputWrapper>
<InputWrapper>
<CurrencyEuro />
<Input type="text" placeholder="Icon" />
</InputWrapper>
<InputWrapper>
<Input type="text" placeholder="Button" />
<Button size="sm" variant="link" mode="icon" className="size-5 -me-0.5">
<Xmark />
</Button>
</InputWrapper>File Input
Input for file uploads.
import { Input } from "@tilt-legal/cubitt-components/primitives";
<Input type="file" />;Copy to Clipboard
Input with a copy-to-clipboard button.
import {
useRef } from "react";
import { useBoolean, useCopyToClipboard, useDebounceCallback } from "@tilt-legal/cubitt-components/utilities/hooks";
import { Button } from "@tilt-legal/cubitt-components/primitives";
import { Input, InputWrapper } from "@tilt-legal/cubitt-components/primitives";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@tilt-legal/cubitt-components/primitives";
import {
Check,
Copy } from "@tilt-legal/cubitt-icons/ui/outline";
export default function CopyToClipboardExample() {
const { value: copied,
setFalse,
setTrue } = useBoolean(false);
const [,
copyToClipboard] = useCopyToClipboard();
const resetCopied = useDebounceCallback(() => {
setFalse();
},
2000);
const inputRef = useRef<HTMLInputElement>(null);
const handleCopy = async () => {
if (!inputRef.current) {
return;
}
const success = await copyToClipboard(inputRef.current.value);
if (!success) {
return;
}
setTrue();
resetCopied();
};
return (
<InputWrapper>
<Input
type="email"
placeholder="Copy to clipboard"
defaultValue="pnpm install @tilt-legal/cubitt-components"
ref={inputRef}
/>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger
render={
<Button
onClick={handleCopy}
variant="link"
disabled={copied}
className="-me-3.5"
/>
}
>
{copied ? (
<Check className="stroke-green-600" size={16} />
) : (
<Copy size={16} />
)}
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">
Copy to clipboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputWrapper>
);
}Clearable Input
Input with a clear button.
import { useRef,
useState } from "react";
import { Button } from "@tilt-legal/cubitt-components/primitives";
import { Input, InputWrapper } from "@tilt-legal/cubitt-components/primitives";
import {
Xmark } from "@tilt-legal/cubitt-icons/ui/outline";
export default function ClearableExample() {
const [inputValue,
setInputValue] = useState("Click to clear");
const inputRef = useRef<HTMLInputElement>(null);
const handleClearInput = () => {
setInputValue("");
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<InputWrapper>
<Input
placeholder="Type some input"
ref={inputRef}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
{inputValue !== "" && (
<Button
onClick={handleClearInput}
variant="link"
className="-me-4"
disabled={inputValue === ""}
>
<Xmark size={16} />
</Button>
)}
</InputWrapper>
);
}Sizes
Input fields in different sizes.
import { Input } from "@tilt-legal/cubitt-components/primitives";
<Input type="text" size="sm" placeholder="Small" />
<Input type="text" placeholder="Medium" />
<Input type="text" size="lg" placeholder="Large" />Inline
Use variant="inline" for inputs that look like text. Useful for editable titles, inline editing, or any context where you want the input to blend with surrounding text.
import { Input } from "@tilt-legal/cubitt-components/primitives";
<Input
variant="inline"
className="text-2xl font-bold"
defaultValue="Page title"
/>
<p className="mt-2">
This is an example of an inline input that looks like editable text.
</p>URL State
Input with URL state synchronization.
import { Input } from "@tilt-legal/cubitt-components/primitives";
<Input
type="text"
placeholder="Type to update URL"
paramName="search"
defaultValue=""
/>;API Reference
Input
The main input component for text entry. Built on Base UI Input with additional URL state management capabilities.
| Prop | Type | Default | Description |
|---|---|---|---|
type | string | "text" | Input type (text, email, password, etc.) |
variant | "default" | "inline" | "default" | Visual style. Use inline for text-like inputs |
size | "sm" | "md" | "lg" | "md" | Size of the input (ignored when variant="inline") |
placeholder | string | - | Placeholder text |
disabled | boolean | false | Whether the input is disabled |
readOnly | boolean | false | Whether the input is read-only |
className | string | - | Additional CSS classes |
URL State Props
The following props enable URL state management by syncing the input value with URL parameters via TanStack Router search params. When paramName is provided, the input's value will be reflected in the URL.
| Prop | Type | Default | Description |
|---|---|---|---|
paramName | string | - | URL parameter name for syncing state with URL. When provided, enables URL state management. |
paramValue | string | - | Controlled value for the URL parameter (syncs with input value). |
onUrlValueChange | (value: string | null) => void | - | Callback when URL parameter value changes. |
paramClearOnDefault | boolean | true | Remove URL param when value equals default. |
paramThrottle | number | - | Throttle URL updates in milliseconds. |
paramDebounce | number | - | Debounce URL updates in milliseconds. |
InputAddon
A decorative addon element for the input.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | Size to match input |
className | string | - | Additional CSS classes |
InputGroup
Container for attaching InputAddon elements to an input. Each element maintains its own visual boundary.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
InputWrapper
Container for placing icons or buttons inside an input. Elements appear embedded within a single field. Size is automatically detected from the Input inside.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |