195 lines
5.5 KiB
TypeScript
195 lines
5.5 KiB
TypeScript
import { useForm } from "@tanstack/react-form";
|
|
|
|
interface MyFormProps {
|
|
onSubmit?: (values: {
|
|
username?: string;
|
|
age?: string;
|
|
password?: string;
|
|
}) => void;
|
|
}
|
|
export function MyForm({ onSubmit }: MyFormProps) {
|
|
const form = useForm({
|
|
defaultValues: {
|
|
username: "",
|
|
age: "",
|
|
password: "",
|
|
},
|
|
|
|
onSubmit: async ({ value }) => {
|
|
onSubmit?.(value);
|
|
console.log("Form submitted successfully:", value);
|
|
alert(JSON.stringify(value, null, 2));
|
|
},
|
|
});
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
maxWidth: "400px",
|
|
margin: "20px auto",
|
|
fontFamily: "sans-serif",
|
|
}}
|
|
>
|
|
<h2>Registration Form (TanStack Form)</h2>
|
|
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
form.handleSubmit();
|
|
}}
|
|
>
|
|
<form.Field
|
|
name="username"
|
|
validators={{
|
|
onChange: ({ value }) => {
|
|
if (!value) return "Full name is required";
|
|
if (!/^[a-zA-Za-z\s]+$/.test(value)) {
|
|
return "Please enter letters only";
|
|
}
|
|
return undefined;
|
|
},
|
|
}}
|
|
>
|
|
{(field) => (
|
|
<div style={{ marginBottom: "15px" }}>
|
|
<label
|
|
htmlFor={field.name}
|
|
style={{ display: "block", marginBottom: "5px" }}
|
|
>
|
|
Full Name (Letters only):
|
|
</label>
|
|
<input
|
|
id={field.name}
|
|
name={field.name}
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
style={{
|
|
width: "100%",
|
|
padding: "8px",
|
|
boxSizing: "border-box",
|
|
}}
|
|
/>
|
|
{field.state.meta.errors.length > 0 && (
|
|
<span style={{ color: "red", fontSize: "12px" }}>
|
|
{field.state.meta.errors.join(", ")}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
</form.Field>
|
|
|
|
<form.Field
|
|
name="age"
|
|
validators={{
|
|
onChange: ({ value }) => {
|
|
if (!value) return "Age is required";
|
|
if (isNaN(Number(value))) {
|
|
return "Please enter numbers only";
|
|
}
|
|
if (Number(value) < 18) {
|
|
return "Age must be at least 18";
|
|
}
|
|
return undefined;
|
|
},
|
|
}}
|
|
>
|
|
{(field) => (
|
|
<div style={{ marginBottom: "15px" }}>
|
|
<label
|
|
htmlFor={field.name}
|
|
style={{ display: "block", marginBottom: "5px" }}
|
|
>
|
|
Age (Numbers only):
|
|
</label>
|
|
<input
|
|
id={field.name}
|
|
name={field.name}
|
|
type="number"
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
style={{
|
|
width: "100%",
|
|
padding: "8px",
|
|
boxSizing: "border-box",
|
|
}}
|
|
/>
|
|
{field.state.meta.errors.length > 0 && (
|
|
<span style={{ color: "red", fontSize: "12px" }}>
|
|
{field.state.meta.errors.join(", ")}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
</form.Field>
|
|
|
|
<form.Field
|
|
name="password"
|
|
validators={{
|
|
onChange: ({ value }) => {
|
|
if (!value) return "Password is required";
|
|
if (value.length < 8) {
|
|
return "Password must be at least 8 characters long";
|
|
}
|
|
return undefined;
|
|
},
|
|
}}
|
|
>
|
|
{(field) => (
|
|
<div style={{ marginBottom: "15px" }}>
|
|
<label
|
|
htmlFor={field.name}
|
|
style={{ display: "block", marginBottom: "5px" }}
|
|
>
|
|
Password:
|
|
</label>
|
|
<input
|
|
id={field.name}
|
|
name={field.name}
|
|
type="password"
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
style={{
|
|
width: "100%",
|
|
padding: "8px",
|
|
boxSizing: "border-box",
|
|
}}
|
|
/>
|
|
{field.state.meta.errors.length > 0 && (
|
|
<span style={{ color: "red", fontSize: "12px" }}>
|
|
{field.state.meta.errors.join(", ")}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
</form.Field>
|
|
|
|
<form.Subscribe
|
|
selector={(state) => [state.canSubmit, state.isSubmitting]}
|
|
>
|
|
{([canSubmit, isSubmitting]) => (
|
|
<button
|
|
type="submit"
|
|
disabled={!canSubmit}
|
|
style={{
|
|
width: "100%",
|
|
padding: "10px",
|
|
backgroundColor: canSubmit ? "#007bff" : "#ccc",
|
|
color: "white",
|
|
border: "none",
|
|
borderRadius: "4px",
|
|
cursor: canSubmit ? "pointer" : "not-allowed",
|
|
}}
|
|
>
|
|
{isSubmitting ? "Submitting..." : "Sign Up"}
|
|
</button>
|
|
)}
|
|
</form.Subscribe>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|