Shadcn Dialog + Form Error: React.Children.only
Hello, I'm want to use a From from shadcn inside a dialog from shadcn but I have this error :
Error: React.Children.only expected to receive a single React element child.
I don't really understand why it's the case I belive the error is caused by the <Form>
"use client";
import React from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
export default function CreateOrJoinGame({
children,
}: {
children: React.ReactNode;
}) {
return (
<Dialog>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<>
<CreateGameDialog />
</>
</DialogContent>
</Dialog>
);
}
"use client";
import React from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
export default function CreateOrJoinGame({
children,
}: {
children: React.ReactNode;
}) {
return (
<Dialog>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<>
<CreateGameDialog />
</>
</DialogContent>
</Dialog>
);
}
4 Replies
const CreateGameSchema = z.object({
bigBlind: z.string().min(1),
maxPlayers: z.string().min(2),
buyIn: z.string().min(1),
minNumberOfPlayers: z.number().min(2).default(2),
});
export function CreateGameDialog() {
const form = useForm<z.infer<typeof CreateGameSchema>>({
resolver: zodResolver(CreateGameSchema),
defaultValues: {
bigBlind: "",
maxPlayers: "",
buyIn: "",
},
});
async function onSubmit(values: z.infer<typeof CreateGameSchema>) {
console.log(values);
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="bigBlind"
render={({ field }) => (
<FormControl>
<FormLabel>Big blind</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
<FormMessage />
</FormControl>
)}
/>
<FormField
control={form.control}
name="maxPlayers"
render={({ field }) => (
<FormControl>
<FormLabel>Max players</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
<FormMessage />
</FormControl>
)}
/>
<FormField
control={form.control}
name="buyIn"
render={({ field }) => (
<FormControl>
<FormLabel>Buy in</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
<FormMessage />
</FormControl>
)}
/>
<FormItem>
<Button type="submit" variant="full">
Create game
</Button>
</FormItem>
</form>
</Form>
);
}
const CreateGameSchema = z.object({
bigBlind: z.string().min(1),
maxPlayers: z.string().min(2),
buyIn: z.string().min(1),
minNumberOfPlayers: z.number().min(2).default(2),
});
export function CreateGameDialog() {
const form = useForm<z.infer<typeof CreateGameSchema>>({
resolver: zodResolver(CreateGameSchema),
defaultValues: {
bigBlind: "",
maxPlayers: "",
buyIn: "",
},
});
async function onSubmit(values: z.infer<typeof CreateGameSchema>) {
console.log(values);
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="bigBlind"
render={({ field }) => (
<FormControl>
<FormLabel>Big blind</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
<FormMessage />
</FormControl>
)}
/>
<FormField
control={form.control}
name="maxPlayers"
render={({ field }) => (
<FormControl>
<FormLabel>Max players</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
<FormMessage />
</FormControl>
)}
/>
<FormField
control={form.control}
name="buyIn"
render={({ field }) => (
<FormControl>
<FormLabel>Buy in</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
<FormMessage />
</FormControl>
)}
/>
<FormItem>
<Button type="submit" variant="full">
Create game
</Button>
</FormItem>
</form>
</Form>
);
}
Formcontrol only expects 1 react element.
Change your structure to something like this:
if you wanted to have what you already have just wrap it in a framgment:
Generally you can fix the error
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Label</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Label</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="buyIn"
render={({ field }) => (
<FormControl>
<>
<FormLabel>Buy in</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
</>
<FormMessage />
</FormControl>
)}
/>
<FormField
control={form.control}
name="buyIn"
render={({ field }) => (
<FormControl>
<>
<FormLabel>Buy in</FormLabel>
<Input {...field} className="rounded-2xl" type="number" />
</>
<FormMessage />
</FormControl>
)}
/>
React.Children.only expected to receive a single React element child.
by wrapping your items in a fragment (which adds no extra markup) or your could wrap in a simple div
Thanks, the error wasn't pointing me to form it was confusing
That's alright i have had the same issue before, and a bit confusing if you have fixed it else where by accident