Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelogKontakt
    1. Startseite
    2. Blog
    3. Komponenten-Guides
    4. Shadcn Number Input: Stepper, Min, Max und Dezimalzahlen
    Read in English
    1. Blog
    2. Komponenten-Guides
    3. Shadcn Number Input: Stepper, Min, Max und Dezimalzahlen
    Komponenten-Guides
    Komponenten-Guides

    Shadcn Number Input: Stepper, Min, Max und Dezimalzahlen

    SR
    Serban Rusu · Gründer von Wingo UI
    6. Nov. 2026 · 8 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Warum enttäuscht type="number" in einem shadcn-Formular?
    2. Wie entferne ich die Pfeile aus einem shadcn number input?
    3. Was sollte ein guter Number Input stattdessen tun?
    4. Wie baue ich das mit dem Number Input von Wingo UI?
    5. Ist er barrierefrei und auf dem Smartphone gut bedienbar?
    6. Wann ist ein Currency Input das bessere Feld?
    7. Bekomme ich ein ordentliches Zahlenfeld nur mit kostenlosen Komponenten?
    8. Was sind die typischen Stolperfallen?
    9. Wie geht es weiter?
    10. Häufige Fragen
      1. Hat shadcn/ui einen Number Input?
      2. Wie entferne ich die Pfeile aus einem shadcn number input?
      3. Wie erlaube ich Dezimalzahlen in einem React Number Input?
      4. Wie setze ich min und max bei einem React Number Input?
      5. Warum liefert mein React Number Input einen String?

    Kurz gesagt

    shadcn/ui hat Stand November 2026 keinen Number Input, und der übliche Ersatz, ein Input mit type="number", ändert sich beim Scrollen, zeigt winzige Pfeile, lehnt in vielen Setups ein Dezimalkomma ab und liefert dir bei halb getippten Werten einen leeren String. Ein besserer shadcn number input ist ein Textfeld mit inputMode="decimal", Parsing nach Locale, Buttons für + und -, die beim Gedrückthalten wiederholen, min, max und step, die beim Verlassen greifen, und Intl-Formatierung im Ruhezustand. Der Number Input von Wingo UI (Pro) kann all das, und der kostenlose Input mit den number-format-Helfern deckt ein einfacheres Feld ab.

    Veröffentlicht am 6. Nov. 2026

    Du brauchst ein Feld für eine Menge, ein Gewicht oder einen Preis, suchst nach einem shadcn number input und stellst fest: Es gibt keinen. Die Liste von shadcn/ui hat Input, Input Group und Field (geprüft im November 2026), also greifst du zu <Input type="number" />. In der Demo klappt das, dann kommen echte Nutzer: Jemand scrollt über dem fokussierten Feld, und der Preis sinkt um 3. Jemand anderes tippt 2,5 in einem Browser, der das Komma ablehnt, und dein State bekommt "" statt einer Zahl. Dieser Guide zeigt, was type="number" falsch macht, was ein gutes Zahlenfeld stattdessen tut und wie du eins baust: mit dem Number Input von Wingo UI oder mit dem kostenlosen Input, wenn dir die Grundlagen reichen.

    Warum enttäuscht type="number" in einem shadcn-Formular?

    Weil es für Werte gedacht ist, die man mit einem Spinner hoch- und runterzählt, während die meisten Formulare Werte abfragen, die Leute eintippen. Der Hinweis zur Barrierefreiheit bei MDN rät selbst, darauf zu verzichten, wenn der Spin-Button keine Rolle spielt, und warnt davor, dass Nutzer eine Zahl versehentlich erhöhen (MDN, input type="number" (opens in a new tab), gelesen im November 2026). Das Team des GOV.UK Design System ist 2020 davon abgerückt, nachdem es Probleme bei der Bedienbarkeit gefunden hatte, darunter Bugs mit den assistiven Technologien Dragon und NVDA (GDS-Blog, Februar 2020 (opens in a new tab)). Diese Probleme triffst du in einer React-App:

    1. Das Mausrad kann den Wert ändern. Du fokussierst das Feld, scrollst, um den Rest des Formulars zu lesen, und in manchen Browsern verschiebt sich die Zahl. Das merkt niemand, bis die Bestellung falsch ist.
    2. Die Pfeile sind winzig. Die nativen Spin-Buttons sind auf dem Desktop ein kleines Pfeilpaar und fehlen in Browsern auf dem Smartphone meist ganz. Als Hauptbedienung taugen sie also nicht, und auf dem Desktop machen sie das Feld trotzdem unruhig.
    3. Dezimalzahlen hängen von Browser und step ab. Mit dem Standardwert step="1" ist 2.5 ungültig. Ein Number Input mit Komma als Dezimaltrennzeichen klappt in manchen Browsern für manche Locales, in anderen nicht.
    4. Der Wert ist ein String, und manchmal ist er leer. Solange der Text keine gültige Zahl ist (-, 1e, 2,5, wo das Komma nicht akzeptiert wird), ist event.target.value gleich "". Das Feld zeigt den Text weiter an, aber dein State, deine Validierung und alles, was daraus abgeleitet ist, sehen ein leeres Feld.
    5. Keine Formatierung. 12,500 oder 2.5 kg kannst du darin nicht anzeigen, nur die rohen Ziffern.
    6. min und max verhindern kein Tippen. Sie begrenzen nur die Pfeile. Eine getippte 5000 in einem Feld mit max="100" bleibt stehen und wird von der Constraint Validation als ungültig markiert. Code, der den Wert aus dem State liest, oder ein Formular mit noValidate bekommt ihn trotzdem.

    Wie entferne ich die Pfeile aus einem shadcn number input?

    Wenn du bei type="number" bleibst, entfernst du die Pfeile mit einer Arbitrary Property und zwei Arbitrary Variants von Tailwind v4:

    tsx
    <input
    type="number"
    className="[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
    />

    appearance: textfield blendet die Pfeile des shadcn number input in Firefox aus, die beiden WebKit-Pseudo-Elemente erledigen das in Chrome und Safari. Damit ist nur die Optik repariert. Mausrad, ArrowUp und ArrowDown ändern den Wert weiterhin, und die Probleme mit Strings und Dezimalzahlen bleiben. Wenn du die Pfeile ohnehin entfernst, ist es sauberer, type="number" ganz aufzugeben.

    Was sollte ein guter Number Input stattdessen tun?

    Nimm einen Text-Input mit Zifferntastatur und gib ihm das Verhalten, das Leute von einem Stepper erwarten:

    • Ein Text-Input mit inputMode. inputMode="decimal" öffnet auf dem Smartphone eine Zifferntastatur mit Dezimaltaste, numeric, wenn nur ganze Zahlen sinnvoll sind. Keine Pannen mit dem Mausrad, keine winzigen Pfeile.
    • Parsing in der Locale der Person. 1,234.5 in en-US und 1.234,5 in de-DE sind dieselbe Zahl, und 2,5 von einer Smartphone-Tastatur mit Komma sollte funktionieren.
    • Echte Buttons für + und -. Groß genug zum Antippen (44px auf Touchscreens), mit Wiederholung beim Gedrückthalten, die nach einer kurzen Pause startet und schneller wird.
    • Tastatur wie bei einem Spinbutton. ArrowUp und ArrowDown ändern um einen Schritt, PageUp und PageDown um einen großen Schritt, Home und End springen zu min und max, dazu role="spinbutton" und aria-valuenow, damit Screenreader den Wert ansagen.
    • min, max und step beim Übernehmen. Lass freies Tippen zu, zeig einen Fehlerring, solange der Wert außerhalb des Bereichs liegt, und begrenze und runde auf den Schritt, wenn das Feld den Fokus verliert.
    • Formatierung im Ruhezustand. Zeig $485,000 oder 2.5 kg, solange das Feld inaktiv ist, und die reine Zahl beim Bearbeiten.
    • Eine Zahl als Ergebnis, kein Text. Dein State bekommt 85 oder null, nie "85 m²".

    Wie baue ich das mit dem Number Input von Wingo UI?

    Installier ihn mit der CLI. Die Field-Anatomie und die number-format-Helfer kommen gleich mit:

    bash
    npx wingo-ui@latest add number-input

    Probier die Demo unten aus: Tipp einen Wert über 1,000 ein, drück dann Tab und sieh zu, wie er zurückspringt. Halt den Button + gedrückt, dann merkst du, wie die Wiederholung schneller wird.

    Tipp 2000 bei Floor area ein und drück Tab: Der Wert wird auf 1,000 begrenzt. Halt + bei Rooms gedrückt, bis der Wert bei 10 stehen bleibt, und scroll dann über dem fokussierten Feld, um ihn schrittweise zu ändern
    $ npx wingo-ui@latest add number-input
    ProDoku: Number Input

    Die wichtigen Props sind min, max, step, decimals, steppers und format. Hier drei typische Felder: eine Menge, ein Gewicht mit einer Nachkommastelle und ein Preis:

    tsx
    "use client";
    import { useState } from "react";
    import { NumberInput } from "@/components/ui/number-input";
    export function ShipmentDetails() {
    const [boxes, setBoxes] = useState<number | null>(2);
    const [weight, setWeight] = useState<number | null>(12.5);
    return (
    <form className="flex flex-col gap-4">
    <NumberInput
    name="boxes"
    label="Pakete"
    steppers="split"
    min={1}
    max={20}
    value={boxes}
    onValueChange={setBoxes}
    locale="en-US"
    />
    <NumberInput
    name="weight"
    label="Gewicht pro Paket"
    step={0.1}
    min={0.1}
    max={70}
    format={{ style: "unit", unit: "kilogram" }}
    value={weight}
    onValueChange={setWeight}
    locale="en-US"
    />
    <NumberInput
    name="declaredValue"
    label="Warenwert"
    currency="USD"
    decimals={0}
    step={50}
    min={0}
    defaultValue={1200}
    onValueCommit={(value) => console.log("Gespeichert:", value)}
    locale="en-US"
    />
    </form>
    );
    }

    Ein paar Details, die du kennen solltest:

    • step legt auch die Genauigkeit fest. step={0.1} behält eine Nachkommastelle und schaltet die Smartphone-Tastatur auf Dezimal um. Ein React Number Input mit Dezimalzahlen braucht also kein zusätzliches Prop. decimals überschreibt das, wenn Schritt und Genauigkeit auseinandergehen.
    • Schritte zählen ab min. Mit min={1} und step={5} geht + auf 1, 6, 11. Ein Wert, der nicht auf dem Raster liegt, springt zuerst auf den nächsten Rasterwert.
    • clampBehavior bestimmt, wie streng min und max sind. Der Standard blur lässt dich außerhalb des Bereichs tippen, zeigt den roten Ring und begrenzt beim Verlassen. strict verweigert einen Tastendruck, der den Wert nur weiter aus dem Bereich schieben kann. none begrenzt nie, für den Fall, dass dein Schema validiert.
    • onValueChange oder onValueCommit. Der erste feuert bei jedem Tastendruck und jedem Stepper-Schritt. Der zweite feuert einmal pro Bearbeitung (beim Verlassen, bei Enter, beim Loslassen eines gehaltenen Steppers). Dorthin gehört ein fetch oder eine Neuberechnung des Preises.
    • Das Mausrad lässt sich abschalten. Es ändert den Wert nur, solange das Feld fokussiert ist und der Mauszeiger darüber liegt, und die Seite scrollt in diesem Moment nicht. Übergib wheel={false} für Felder in langen Formularen, durch die man scrollt.
    • name sendet eine Zahl. Ein versteckter Input trägt "12.5" mit Dezimalpunkt. FormData und Server Actions bekommen also einen Wert, den du an Number() übergeben kannst, egal in welcher Locale das Feld anzeigt.

    Dasselbe Feld parst so, wie die Locale Zahlen schreibt. Hier läuft es auf Deutsch mit halben Schritten, also tipp 12,5 und drück Tab:

    In de-DE: Tipp 12,5 und drück Tab, im Ruhezustand steht dann 12,5 m² da. Drück zweimal ArrowUp, jedes Mal kommen 0.5 dazu
    $ npx wingo-ui@latest add number-input
    ProDoku: Number Input

    Ist er barrierefrei und auf dem Smartphone gut bedienbar?

    Das Feld ist ein echtes <input> mit role="spinbutton", aria-valuenow, aria-valuemin, aria-valuemax und einem aria-valuetext, das den formatierten Wert vorliest. Ein Screenreader sagt also „85 m²“ statt „85“. Die Buttons für + und - haben zugängliche Namen (incrementLabel und decrementLabel, standardmäßig „Increase“ und „Decrease“) und werden an den Grenzen gedimmt. Label, Beschreibung und Fehler kommen aus der gemeinsamen Field-Anatomie, verknüpft über htmlFor und aria-describedby, sodass sich das Feld wie jeder andere Input ins Formular einfügt.

    Auf dem Smartphone ist der Text 16px groß, damit iOS beim Fokus nicht zoomt, die Box in md wächst auf 44px, und jeder Stepper bekommt eine Trefferfläche von 44px. steppers="split" setzt - nach links und + nach rechts, den Wert in die Mitte. Für Mengen unter dem Daumen funktioniert dieses Layout am besten. Übereinanderliegende Chevrons mit stacked sind eine Desktop-Gewohnheit; auf Touchscreens werden daraus zwei Buttons von 44px nebeneinander.

    Wann ist ein Currency Input das bessere Feld?

    Wenn die Zahl Geld ist und sich die Währung ändern kann, oder wenn Leute große Beträge tippen. Ein Number Input mit currency="USD" reicht für einen Preis in fester Währung, den man meist per Stepper ändert. Ein Geldfeld, in das Leute tippen, braucht mehr: Tausendertrennzeichen schon beim Tippen, ohne dass der Cursor springt, Auffüllen auf die Nachkommastellen der Währung (2 für USD, 0 für JPY, 3 für BHD), optional eine Währungsauswahl und Chips für schnelle Beträge. Das ist der Currency Input:

    Klick in den Betrag, tipp 1234.5 und drück Tab: Er wird auf 1,234.50 aufgefüllt. Öffne den Währungs-Button und wähl einen anderen Code: Der Betrag wird nicht umgerechnet
    $ npx wingo-ui@latest add currency-input
    ProDoku: Currency Input
    tsx
    import { CurrencyInput } from "@/components/ui/currency-input";
    <CurrencyInput
    name="amount"
    currencyName="currency"
    label="Betrag"
    locale="en-US"
    currencies={["USD", "EUR", "GBP"]}
    defaultValue={250}
    min={1}
    />

    Die Cursor-Mathematik und das Parsing dahinter erklärt der Guide zum React Currency Input Schritt für Schritt.

    Bekomme ich ein ordentliches Zahlenfeld nur mit kostenlosen Komponenten?

    Ja, wenn du ohne Stepper und ohne Wiederholung beim Gedrückthalten auskommst. Der kostenlose Input behandelt type="number" bereits als Textfeld mit Dezimaltastatur, das Mausrad ändert ihn also nie. Die kostenlosen number-format-Helfer liefern dir Parsing nach Locale, Begrenzen und Runden auf den Schritt:

    tsx
    "use client";
    import { useState } from "react";
    import { Input } from "@/components/ui/input";
    import { clamp, formatNumber, parseNumber, snapToStep } from "@/lib/number-format";
    export function WeightField({ locale = "en-US" }: { locale?: string }) {
    const [text, setText] = useState("12.5");
    // eingabe parsen, begrenzen, auf 0.1 runden und formatiert zurückgeben
    function commit() {
    const parsed = parseNumber(text, locale);
    if (parsed === null) return setText("");
    const value = clamp(snapToStep(parsed, 0.1), 0.1, 70);
    setText(formatNumber(value, locale, { maximumFractionDigits: 1 }));
    }
    return (
    <Input
    type="number"
    name="weight"
    label="Gewicht pro Paket"
    suffix="kg"
    value={text}
    onValueChange={setText}
    onBlur={commit}
    />
    );
    }

    Installier beides mit npx wingo-ui@latest add input number-format. Parse text in deinem Submit-Handler noch einmal, oder halte eine separate Zahl im State. Brauchst du Stepper, die Tastenbelegung und die formatierte Anzeige, spart dir der Number Input aus Pro an dieser Stelle ein paar hundert Zeilen.

    Was sind die typischen Stolperfallen?

    • Den formatierten String speichern. Halte number | null im State und im Schema, und formatiere nur für die Anzeige.
    • Bei jedem Tastendruck begrenzen. Mit max={100} wird 150 auf dem Weg zu 15 auf 100 begrenzt, und die Eingabe ist weg. Begrenze beim Verlassen des Felds.
    • Rundungsfehler bei Schritten. 0.1 + 0.2 ergibt 0.30000000000000004. Runde nach jedem Schritt auf die Nachkommastellen des Schritts (roundTo in number-format erledigt das).
    • Einen Number Input für IDs verwenden. Postleitzahlen, Kartennummern und Telefonnummern sind Ziffernfolgen, keine Mengen. Nimm einen normalen Text-Input mit inputMode="numeric" und einem Wert für autoComplete.

    Für den Rest des Formulars, also Labels, Fehler und Validierung mit Zod, lies den Guide zu React-Formularkomponenten und die anderen Beiträge in den Komponenten-Guides. Wenn du Number Inputs auf einer ganzen Seite sehen willst: Die Vorlage ROI Calculator verbindet mehrere davon mit einem Live-Ergebnis.

    Wie geht es weiter?

    Fang mit dem kostenlosen Input und den number-format-Helfern an, wenn ein einfaches Zahlenfeld reicht: Mit einem kostenlosen Konto (nur E-Mail) bekommst du den Quellcode. Brauchst du Stepper, Wiederholung beim Gedrückthalten und Intl-Formatierung, sind Number Input und Currency Input Teil von Pro; die Preise stehen auf der Preisseite.

    Komponenten in diesem Artikel

    • Number Input

      A React number input to type or step values: steppers with hold to repeat, min, max and step, and Intl formatting for money and units.

      Pro
    • Currency Input

      A React currency input: a money field formatted per locale as you type, with an optional currency selector and quick amount presets.

      Pro
    • Input

      A React text input: icons and addons inside the box, a clear button, a loading spinner, a character counter and floating labels.

      Free
    • Field

      A React form field wrapper every control shares: label, hint, animated error and counter, fieldsets, and the box recipe all inputs use.

      Free

    Häufige Fragen

    Hat shadcn/ui einen Number Input?

    Nein. Stand November 2026 enthält die offizielle Komponentenliste von shadcn/ui Input, Input Group, Input OTP und Field, aber keinen Number Input und kein Number Field. Die meisten Projekte nehmen Input mit type="number" oder eine Komponente aus der Community.

    Wie entferne ich die Pfeile aus einem shadcn number input?

    Ergänze im className des Inputs [appearance:textfield] für Firefox und [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none für Chrome und Safari. Mausrad und Pfeiltasten ändern den Wert trotzdem, also überleg dir stattdessen einen Text-Input mit inputMode="decimal".

    Wie erlaube ich Dezimalzahlen in einem React Number Input?

    Bei type="number" setzt du step="any" oder einen Dezimalschritt wie 0.01, sonst markiert der Browser 2.5 als ungültig. Bei einem Text-Input nimmst du inputMode="decimal" und parst den Text selbst, damit 2.5 und 2,5 beide funktionieren.

    Wie setze ich min und max bei einem React Number Input?

    Die nativen Attribute min und max bremsen nur die Pfeile. Ein getippter Wert außerhalb des Bereichs wird trotzdem angenommen und nur als ungültig markiert. Begrenz die geparste Zahl beim Verlassen des Felds und dimm den Button für + oder -, sobald der Wert eine Grenze erreicht.

    Warum liefert mein React Number Input einen String?

    Der Wert jedes Inputs ist ein String, und bei type="number" ist er leer, solange der Text noch keine gültige Zahl ist, etwa "1e" oder "-". Nimm event.target.valueAsNumber oder parse den String, und speichere null für ein leeres Feld.

    In deinem Projekt ausprobieren

    Number Input

    Pro

    A React number input to type or step values: steppers with hold to repeat, min, max and step, and Intl formatting for money and units.

    75 Komponenten kostenlos, ohne Konto. Pro ab 8 $ im Monat.

    Number Input live öffnenPreise ansehen
    • Formulare
    • Number Input
    • shadcn
    • Intl

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Komponenten-Guides

    React Currency Input: Intl-Formatierung ohne Cursor-Sprünge

    So baust du einen React Currency Input, der beim Tippen mit Intl formatiert, den Cursor stehen lässt, das Symbol nach Locale setzt und eine reine Zahl sendet.

    SRSerban Rusu·16. Okt. 2026·10 Min. Lesezeit
    Komponenten-Guides

    CUI prüfen: rumänische Steuer-ID mit TypeScript und Zod

    CUI prüfen in TypeScript: die Prüfziffer mit dem Schlüssel 753217532 Schritt für Schritt, das Präfix RO, eine zod-Regel, ein React-Feld und die ANAF-Abfrage.

    SRSerban Rusu·9. Okt. 2026·10 Min. Lesezeit
    Komponenten-Guides

    React Form Components: barrierefrei, mit Zod und mobil

    React Form Components mit einer Anatomie (Label, Hinweis, Fehler, Zähler), angebunden an react-hook-form und zod und fürs Smartphone gebaut, mit vollem Code.

    SRSerban Rusu·9. Okt. 2026·26 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Artikel, Produktneuheiten und gelegentlich Angebote von Wingo UI. Wir zählen Klicks, damit es relevant bleibt.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Für Teams
    • Theme-Generator

    Ressourcen

    • Doku
    • Kontakt
    • Programme
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Vergleiche

    • Wingo UI vs. Premium-Kits
    • Wingo UI vs. shadcn/ui
    • shadcn/ui-Alternativen
    • MUI-Alternativen
    • Tailwind-Plus-Alternativen
    • Magic-UI-Alternativen
    • Kostenlose Komponenten

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI