🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 9 Min Lesezeit
0

We wanted a simple forms API, so I built my own library

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

| is that it should feel closer to writing HTML than to configuring a library.



You write an input the way you'd write any other React component. At its simplest, gform renders a native <input>, and standard attributes like className and placeholder go right on GInput, which forwards them through:




CODE
<GInput formKey="email" type="email" required className="input" placeholder="Email" />






Need custom markup or inline errors? Pass an element. You spread props onto your input like you always would, and input.error and input.errorText are right there where you're rendering it, so no digging into formState.errors.email?.message, no Controller and no resolver setup:




CODE
<GInput formKey="email"
type="email"
required
placeholder="Email"
element={(input, props) => (
<div>
<input {...props} />
{input.error && <small>{input.errorText}</small>}
</div>
)}
/>






Standard input attributes belong on GInput (they're forwarded either way); keep custom props on your element.






Dependent fields are where it actually hurts



Almost every real form has at least one. A city dropdown that only makes sense once you've picked a country, a street list that reloads when the city changes, that sort of thing.



The usual way to handle this looks something like:




CODE
const [cities, setCities] = useState([]);
const [loading, setLoading] = useState(false);
const country = watch("country");

useEffect(() => {
if (!country) return;
setLoading(true);
loadCities(country).then((cities) => {
setCities(cities);
setValue("city", cities[0]);
setLoading(false);
});
}, [country]);






It works, but none of it actually lives in the form. It's wired together outside it, in your component, with a pile of useState and duct tape.



So I came up with another solution:




CODE
<GInput formKey="city"
fetchDeps={["country"]}
fetch={async (input, fields) => {
const cities = await loadCities(fields.country.value);
return { options: cities, value: cities[0] };
}}
element={renderCity}
/>






fetchDeps watches the country field. When it changes, fetch runs, loads the new cities, and pushes the result back into form state for you. The dependency tracking and the dispatch live inside the form instead of in your component.






Adding custom data to a field



That fetch attaches data automatically. You can do the same by hand with dispatchChanges: it merges whatever you give it onto the field's state, so you can park extra data there: a list of options, a loading flag, a label, whatever. then read it straight back in element.



Say you've loaded a city list and want to keep the selected value and the options together on the field:




CODE
state.city.dispatchChanges({
value: cities[0],
options: cities, // custom data, rides along on the field
});






Then read it where you render the input:




CODE
<GInput formKey="city"
element={(input, props) => (
<select {...props}>
{input.options?.map((c) => (
<option key={c} value={c}>{c}</option>
))}
</select>
)}
/>






No extra useState, no second source of truth. Add { validate: true } as a second argument if you passed a new value and if it should re-run validation.






What about native submission and Next.js Server Actions?



Native <form> submission and Next.js Server Actions work without any extra wiring. Submit through action instead of onSubmit, and gform still runs your client validation first and blocks an invalid submit before it ever reaches the server:




CODE
<GForm action={myServerAction}>
<GInput formKey="email" type="email" required element={/* render input */} />
<button>Submit</button>
</GForm>









Validation



Native HTML constraints (required, minLength, pattern, type, and the rest) work out of the box. The only thing you add is the message. Here's a full subscribe form:




CODE
import {GForm, GInput, GValidator} from "gform-react";

interface ISubscribeForm {
name: string;
email: string;
}

const baseValidator = new GValidator().withRequiredMessage(input => `${input.name} is required`);

// '*' is the default for every field; a message can be a string or a function
const validators = {
"*": baseValidator,
name: new GValidator(baseValidator).withMinLengthMessage("At least 2 characters"),
email: new GValidator(baseValidator).withPatternMismatchMessage("Enter a valid email")
};

export const SubscribeForm = () => {
return (
<GForm<ISubscribeForm>
validators={validators}
onSubmit={(state, e) => {
e.preventDefault();
console.log(state.toRawData()); // { name, email }
}}>
{(state) => (
<>
<GInput formKey="name"
required
minLength={2}
placeholder="Name"
element={(input, props) => (
<div>
<input {...props} />
{input.error && <small>{input.errorText}</small>}
</div>
)}
/>
<GInput formKey="email"
type="email"
required
pattern="[^@\s]+@[^@\s]+\.[^@\s]+"
placeholder="Email"
element={(input, props) => (
<div>
<input {...props} />
{input.error && <small>{input.errorText}</small>}
</div>
)}
/>
<button disabled={state.isInvalid}>Subscribe</button>
</>
)}
</GForm>
);
}






The pattern on email is enough for gform to show your patternMismatch message instead of the browser's generic typeMismatch (pattern wins when both fail). A message can be a plain string or a function of the input, and "*" applies a validator to every field unless you override it, the way email does here.



Need a rule native HTML can't express? Add a custom check. You return true to mark the field invalid (you're answering "is this broken?"), and set the message on input.errorText:




CODE
const validators = {
fullName: new GValidator().withCustomValidation((input) => {
input.errorText = "please pick another name";
return input.value === "admin"; // true means invalid
})
};






Prefer a schema? Hand withSchema a Zod, Valibot, or ArkType, Joi, or any other library that implements - any library implementing the spec works out of the box (Zod, Valibot, ArkType, Yup, …); drive the whole form from one schema via GValidator.withSchema / withSchemaAsync, including object-level cross-field rules - with zero runtime dependencies


  • Custom & async validation - add any rule via withCustomValidation, including asynchronous server-side checks with withCustomValidationAsync


  • Cross-field validation - re-validate a field when another changes (e.g. confirm-password) via validatorDeps


  • Deeply Nested Forms - structure forms however you like, split a big form into focused and reusable components


  • Dynamic fields - add or remove fields at runtime without losing state


  • Native <form> actions - fully supports browser‑level form submission, including action, method, and HTTP
    navigation, with no JavaScript required


  • Next.js Server Actions support - works seamlessly with Server Actions through standard <form> submissions, with
    no special adapters or client‑side wiring


  • Custom data on any input - attach arbitrary data to a field via dispatchChanges (option lists,
    loading flags, fetched metadata); it's kept in form state for your UI, separate from the submitted value


  • Accessibility‑friendly - automatically manages aria-required and aria-invalid


  • File inputs - type="file" stores the real File object (or File[] with multiple), not the C:\fakepath\...
    string


  • React Native support - the same API on web and mobile (via gform-react/native); no adapters, no separate mental model






  • The honest part



    gform-react was a private library. There aren't years of tutorials, a pile of Stack Overflow answers, or a big ecosystem around it. I built it because we needed it, we run it in production, and I fix the rough edges as we hit them.



    If you're happy with your current setup, you probably don't need it.



    But if you've ever stared at a form component and wondered why something this basic turned into this much code, it might be worth a look.

    Vollständiger Original-Bericht
    Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
    ↗ Original-Artikel auf dev.to lesen
    Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 0%
    🟡 In Evaluierung 0%
    🟢 Keine Auswirkung 0%
    Spannende Innovation 0%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    3 Quellen
    GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
    1 Quelle
    Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
    1 Quelle
    Major AI platforms go down in unprecedented simultaneous outage
    Ähnliche Beiträge
    🔍 Verwandte News

    Auch interessante Nachrichten We wanted a simple forms API, so I built my own library

    Thematisch verwandte Begriffe: wanted, simple, forms, built · 6 Treffer

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...