React Inputs
One import to your first input
No stylesheet to import. No provider to mount. No configuration. Install it and render it.
Install
npm install @rxova/react-inputsUse
import { CurrencyInput } from '@rxova/react-inputs'
export function Price({ value, onChange }) { // `name` is all it takes to post with the form. return ( <CurrencyInput name="price" locale="de-DE" currency="EUR" value={value} onChange={onChange} /> )}Why this one
Small on purpose, deep where it counts
A short list of inputs, each taken all the way — formatting, caret behaviour, accessibility and native form support treated as the whole job rather than the last mile.
Maintained, in the open
Shipped under the Rxova organisation alongside Journey and use-everywhere. Changesets-driven releases, provenance-signed npm publishes, an API reference generated from source.
Lightweight, and held to it
Every package carries a size budget that CI enforces on each build. Exceed it and the build fails — the number on this page is that budget, not an estimate.
No dependencies to inherit
reactis the only peer. Nothing else reaches your bundle, nothing else can break you, and everything tree-shakes down to what you actually imported.Accessible by construction
Native platform semantics do the work — an interactive rating is a real radiogroup, and an OTP field is one real input. Keyboard, focus and form behaviour come from the browser, and every build is checked with axe.
UX-first, down to the caret
The caret stays where you put it while the value reformats underneath. Paste works. Autofill works. So do IME composition, RTL and server rendering.
Correct on the seams
Bulgarian's space-only-above-9999 grouping, Hindi lakh grouping, Arabic-Indic digits, formatted paste, Chrome's auto-translate rewriting your DOM. The cases that only show up in production.
Proof
Numbers you can go and check
Every figure below is read out of the config that enforces it, at the moment this page is built. None of them is typed by hand, so none of them can quietly go stale.
0
Runtime dependencies
react is the only peer, across every package
10 kB
Whole suite, Brotli
Enforced by size-limit in CI — 5 kB for a single tree-shaken component
95%
Coverage floor, per file
Per-file thresholds, so a thin module cannot hide behind a well-covered one
3
Engines under E2E
chromium, firefox, webkit
0
Accessibility violations
axe-core against wcag2a, wcag2aa, wcag21a, wcag21aa — including RTL and error states
MIT
Licensed, every package
Permissive and unchanged since the first release — use it at work without asking anyone
See for yourself
This is not a screenshot. Edit it.
Switch the locale and watch the grouping, symbol placement, decimal rules and digit system follow — all from Intl, none of it from a regex. Then drag the rating and paste into the code field. The source underneath is editable too.
function PlayWithMe() { // de-DE German · bg-BG space only above 9999 · hi-IN lakh grouping // ar-EG native digits · ja-JP no decimals const CURRENCY = { 'de-DE': 'EUR', 'bg-BG': 'BGN', 'hi-IN': 'INR', 'ar-EG': 'EGP', 'ja-JP': 'JPY' } const [locale, setLocale] = useState('de-DE') const [score, setScore] = useState(3.5) const [code, setCode] = useState('') return ( <div style={{ display: 'grid', gap: 24, justifyItems: 'start' }}> <p style={{ margin: 0, fontSize: 20, fontWeight: 600 }}>Play with me 👋</p> <label> Locale{' '} <select value={locale} onChange={(e) => setLocale(e.target.value)}> {Object.keys(CURRENCY).map((l) => <option key={l}>{l}</option>)} </select> </label> <CurrencyInput aria-label="Amount" locale={locale} currency={CURRENCY[locale]} defaultValue={5000000} /> <Rating value={score} onChange={setScore} precision={0.5} label="Rate it" /> <OtpInput value={code} onChange={setCode} length={6} label="One-time code" /> </div> ) }
Every input has a playground like this one on its own page, alongside the full prop reference. See the whole suite →
Budgets
A ceiling, not an aspiration
Take the whole suite or take one input — either way you know the cost before you install, because the build fails when it moves.
| Package | You import | Brotli |
|---|---|---|
| @rxova/react-intl-currency-input | { CurrencyInput } | ≤ 3.25 kB |
| @rxova/react-intl-currency-input | { useCurrencyInput } | ≤ 3.25 kB |
| @rxova/react-date-input | { DateInput } | ≤ 4 kB |
| @rxova/react-date-input | { useDateInput } | ≤ 3 kB |
| @rxova/react-file-input | { FileInput } | ≤ 4.5 kB |
| @rxova/react-file-input | { useFileInput } | ≤ 3.5 kB |
| @rxova/react-otp-input | { OtpInput } | ≤ 4.5 kB |
| @rxova/react-otp-input | { useOtpInput } | ≤ 2.8 kB |
| @rxova/react-password-input | { PasswordInput } | ≤ 5 kB |
| @rxova/react-password-input | { usePasswordInput } | ≤ 3.25 kB |
| @rxova/react-password-input | { estimateStrength } | ≤ 1.5 kB |
| @rxova/react-phone-input | { PhoneInput } | ≤ 4.55 kB |
| @rxova/react-phone-input | { usePhoneInput } | ≤ 3.7 kB |
| @rxova/react-phone-input | { parsePhone } | ≤ 3 kB |
| @rxova/react-rating-input | { Rating } | ≤ 3 kB |
| @rxova/react-rating-input | { useRating } | ≤ 1.25 kB |
| @rxova/react-tags-input | { TagsInput } | ≤ 4 kB |
| @rxova/react-tags-input | { useTagsInput } | ≤ 3 kB |
| @rxova/react-time-input | { TimeInput } | ≤ 4 kB |
| @rxova/react-time-input | { useTimeInput } | ≤ 3.25 kB |
Headless
Style it with CSS, not with props
There is no stylesheet to import and no theme object to configure. Every component reads its appearance from custom properties and exposes its state as data attributes, so it inherits whatever your app already looks like.
.field { --rx-otp-border: 1px solid var(--my-border); --rx-otp-radius: 8px; --rx-otp-active-ring: 2px solid var(--my-brand);}
.field [data-filled] { font-weight: 600;}