f-ui
Components

Text Inputs

Icon-leading email, URL, and phone fields built on shadcn Input—each installs with a shared icon-leading-input module.

Email, URL, and phone fields each ship as their own registry item; inputs-internals provides the shared icon-leading-input shell. For empty read-only values (tables, readouts), use Empty Value Placeholder—it has its own registry item and documentation page.

Email Input

Installation

Registry item email-input — pulls input and inputs-internals from the registry and declares lucide-react. Files land under components/f-ui/email-input/ and components/f-ui/inputs-internals/ (see the registry manifest).

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/email-input.json
npx shadcn@latest add https://ui.isaacfei.com/r/email-input.json
yarn dlx shadcn@latest add https://ui.isaacfei.com/r/email-input.json
bun x shadcn@latest add https://ui.isaacfei.com/r/email-input.json

With a namespace: npx shadcn@latest add @f-ui/email-input.

Usage

import { EmailInput } from '@/components/f-ui/email-input/email-input';

<EmailInput value={email} onChange={(e) => setEmail(e.target.value)} />

Example

Value:

"use client";

import { useState } from "react";

import { EmailInput } from "@/components/f-ui/email-input/email-input";
import {
  EmptyValuePlaceholder,
  isEmptyDisplayValue,
} from "@/components/f-ui/empty-value-placeholder";

export function EmailInputDemo() {
  const [value, setValue] = useState("");

  return (
    <div className="max-w-sm space-y-3">
      <EmailInput
        value={value}
        onChange={(e) => setValue(e.target.value)}
        aria-label="Email"
      />
      <p className="text-muted-foreground flex flex-wrap items-center gap-x-1 gap-y-0.5 text-xs">
        <span>Value:</span>
        {isEmptyDisplayValue(value) ? (
          <EmptyValuePlaceholder />
        ) : (
          <span className="text-foreground font-medium tabular-nums">{value}</span>
        )}
      </p>
    </div>
  );
}

API Reference

  • Thin wrapper around IconLeadingInput (EmailInput export) with type="email" and a default mail icon in leadingSlot.
  • leadingSlot: optional override for the leading icon.
  • Default placeholder: email@example.com.
  • Inherits standard controlled Input props (value, onChange, disabled, className, aria-*, etc.).

URL Input

Installation

Registry item url-input.

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/url-input.json
npx shadcn@latest add https://ui.isaacfei.com/r/url-input.json
yarn dlx shadcn@latest add https://ui.isaacfei.com/r/url-input.json
bun x shadcn@latest add https://ui.isaacfei.com/r/url-input.json

Namespace: npx shadcn@latest add @f-ui/url-input.

Usage

import { UrlInput } from '@/components/f-ui/url-input/url-input';

<UrlInput value={url} onChange={(e) => setUrl(e.target.value)} />

Example

Value:

"use client";

import { useState } from "react";

import { UrlInput } from "@/components/f-ui/url-input/url-input";
import {
  EmptyValuePlaceholder,
  isEmptyDisplayValue,
} from "@/components/f-ui/empty-value-placeholder";

export function UrlInputDemo() {
  const [value, setValue] = useState("");

  return (
    <div className="max-w-sm space-y-3">
      <UrlInput
        value={value}
        onChange={(e) => setValue(e.target.value)}
        aria-label="URL"
      />
      <p className="text-muted-foreground flex flex-wrap items-center gap-x-1 gap-y-0.5 text-xs">
        <span>Value:</span>
        {isEmptyDisplayValue(value) ? (
          <EmptyValuePlaceholder />
        ) : (
          <span className="text-foreground max-w-full break-all font-medium">
            {value}
          </span>
        )}
      </p>
    </div>
  );
}

API Reference

  • Same pattern as EmailInput with type="url" and a default link icon.
  • Default placeholder: https://.

Phone Input

Installation

Registry item phone-input.

pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/phone-input.json
npx shadcn@latest add https://ui.isaacfei.com/r/phone-input.json
yarn dlx shadcn@latest add https://ui.isaacfei.com/r/phone-input.json
bun x shadcn@latest add https://ui.isaacfei.com/r/phone-input.json

Namespace: npx shadcn@latest add @f-ui/phone-input.

Usage

import { PhoneInput } from '@/components/f-ui/phone-input/phone-input';

<PhoneInput value={phone} onChange={(e) => setPhone(e.target.value)} />

Example

Value:

"use client";

import { useState } from "react";

import { PhoneInput } from "@/components/f-ui/phone-input/phone-input";
import {
  EmptyValuePlaceholder,
  isEmptyDisplayValue,
} from "@/components/f-ui/empty-value-placeholder";

export function PhoneInputDemo() {
  const [value, setValue] = useState("");

  return (
    <div className="max-w-sm space-y-3">
      <PhoneInput
        value={value}
        onChange={(e) => setValue(e.target.value)}
        aria-label="Phone"
      />
      <p className="text-muted-foreground flex flex-wrap items-center gap-x-1 gap-y-0.5 text-xs">
        <span>Value:</span>
        {isEmptyDisplayValue(value) ? (
          <EmptyValuePlaceholder />
        ) : (
          <span className="text-foreground font-medium tabular-nums">{value}</span>
        )}
      </p>
    </div>
  );
}

API Reference

  • Same pattern with type="tel" and a default phone icon.
  • Default placeholder: +1 (555) 000-0000.

On this page