The Kit/Components/Input

Input

Labelled text fields with three focus behaviours: console ring, hairline accent border, sunk well with an accent underline plate.

theme-aware · one self-contained file per variantMIT · copy freely

Apex

Racing-instrument console on layered indigo · proven in F1Peak · see the whole Apex set
loading…
Apex.tsx
"use client";
import * as React from "react";

/* Apex Input - pill field with a focus ring in the accent (instrument console feel). */

export function Input({ label, ...rest }: React.InputHTMLAttributes<HTMLInputElement> & { label?: string }) {
  const [f, setF] = React.useState(false);
  return (
    <label style={{ display: "block", fontFamily: "var(--font-ui)" }}>
      {label && (
        <span style={{
          display: "block", fontFamily: "var(--font-mono)", fontSize: 10,
          textTransform: "uppercase", letterSpacing: "1.2px",
          color: "var(--ink-faint)", marginBottom: 6,
        }}>{label}</span>
      )}
      <input {...rest}
        onFocus={(e) => { setF(true); rest.onFocus?.(e); }}
        onBlur={(e) => { setF(false); rest.onBlur?.(e); }}
        style={{
          width: "100%", padding: "9px 15px", fontSize: 13.5, fontFamily: "var(--font-ui)",
          color: "var(--ink)", background: "var(--surface)", borderRadius: 999,
          border: `1px solid ${f ? "var(--accent)" : "var(--line)"}`,
          boxShadow: f ? "0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent)" : "none",
          outline: "none", transition: "border-color .16s ease, box-shadow .16s ease",
        }} />
    </label>
  );
}

Tifo

Matchday broadsheet on near-black · proven in World Cup 26 · see the whole Tifo set
loading…
Tifo.tsx
"use client";
import React, { useState, useId } from "react";

/* Tifo Input - flat hairline field, sharp corners, accent border on focus. No ring. */

export function Input(
  props: React.InputHTMLAttributes<HTMLInputElement> & { label?: string }
) {
  const { label, style, onFocus, onBlur, id, ...rest } = props;
  const [focus, setFocus] = useState(false);
  const autoId = useId();
  const inputId = id ?? (label ? `${autoId}-inp` : undefined);

  return (
    <span style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      {label ? (
        <label htmlFor={inputId} style={{
          fontFamily: "var(--font-mono)", textTransform: "uppercase",
          fontSize: 10, letterSpacing: "1.2px", color: "var(--ink-faint)",
        }}>{label}</label>
      ) : null}
      <input
        {...rest}
        id={inputId}
        onFocus={(e) => { setFocus(true); onFocus?.(e); }}
        onBlur={(e) => { setFocus(false); onBlur?.(e); }}
        style={{
          borderRadius: 3, background: "var(--surface-2)",
          border: `1px solid ${focus ? "var(--accent)" : "var(--line)"}`,
          color: "var(--ink)", fontFamily: "var(--font-ui)", fontSize: 13.5,
          lineHeight: 1.4, padding: "8px 11px", outline: "none",
          transition: "border-color 120ms ease",
          ...style,
        }}
      />
    </span>
  );
}

Ink

Painted poster plates on deep oil-blue · born in the library · see the whole Ink set
loading…
Ink.tsx
"use client";
import React, { useState, useId } from "react";

/* Ink Input - a flat well sunk into the canvas; focus swaps the underline plate
   to the accent. Labels in condensed caps. No ring, no glow. */

export function Input(
  props: React.InputHTMLAttributes<HTMLInputElement> & { label?: string }
) {
  const { label, style, onFocus, onBlur, id, ...rest } = props;
  const [focus, setFocus] = useState(false);
  const autoId = useId();
  const inputId = id ?? (label ? `${autoId}-inp` : undefined);
  const punch = "color-mix(in srgb, var(--bg) 40%, #000)";

  return (
    <span style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      {label ? (
        <label htmlFor={inputId} style={{
          fontFamily: "var(--font-display)", textTransform: "uppercase",
          fontSize: 11, letterSpacing: "0.07em", fontWeight: 700, color: "var(--ink-dim)",
        }}>{label}</label>
      ) : null}
      <input
        {...rest}
        id={inputId}
        onFocus={(e) => { setFocus(true); onFocus?.(e); }}
        onBlur={(e) => { setFocus(false); onBlur?.(e); }}
        style={{
          borderRadius: 2, background: "color-mix(in srgb, var(--bg) 82%, #000)",
          border: "none",
          boxShadow: focus ? `inset 0 -3px 0 var(--accent), 2px 2px 0 ${punch}` : `inset 0 -3px 0 ${punch}`,
          color: "var(--ink)", fontFamily: "var(--font-ui)", fontSize: 13.5,
          lineHeight: 1.4, padding: "9px 12px", outline: "none",
          transition: "box-shadow 140ms ease",
          ...style,
        }}
      />
    </span>
  );
}

Also in components: Badge · Button · Card