- Published on
Fixing Shadcn/UI Tooltip Triggering Form Validation
- Authors
- Name
- Ripal & Zalak
When building forms in React with Shadcn/UI, react-hook-form, and zod, you may encounter an issue where clicking a button wrapped with a Tooltip component triggers form validation. This guide explains how to resolve this problem effectively.
The Problem
Consider the following scenario: a button wrapped in a Tooltip
component updates a form field when clicked, but also triggers validation on unrelated fields. Here's an example:
export default function JobForm() {
const formSchema = z.object({
jobName: z.string().min(1).max(50),
button: z.string().optional(),
})
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
jobName: '',
button: '',
},
})
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
}
return (
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="jobName"
render={({ field }) => (
<FormItem>
<FormLabel>Job Name</FormLabel>
<FormControl>
<Input placeholder="Input job name" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Controller
name="button"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Button</FormLabel>
<FormControl>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
{' '}
{/* Add asChild here */}
<Button
type="button"
className="mr-2"
onClick={() => form.setValue('button', 'Button 1')}
>
Button 1
</Button>
</TooltipTrigger>
<TooltipContent>
<p>"This is Button 1"</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
</div>
)
}
The Cause
By default, the TooltipTrigger
component renders as a button
element. This behavior conflicts with the Button
component inside it, causing form validation when clicked, even if the button's type
is set to button
.
The Solution
To prevent this, use the asChild
prop on the TooltipTrigger
. This allows the TooltipTrigger
to render its child directly without adding an additional button
element.
Here’s the fixed code:
<TooltipTrigger asChild>
<Button type="button" className="mr-2" onClick={() => form.setValue('button', 'Button 1')}>
Button 1
</Button>
</TooltipTrigger>
Why It Works
The asChild
prop ensures that the TooltipTrigger
doesn’t create its own DOM element. Instead, it uses the child component (in this case, the Button
) as the trigger, eliminating the conflict.
Additional Tips
- Always Specify Button Type: Ensure all buttons in your form have a
type
attribute to explicitly define their behavior (button
,submit
, orreset
). - Validate on Submit Only: Adjust validation settings in
react-hook-form
to trigger validation only on submit if required. - Test with Developer Tools: Inspect the DOM to confirm there are no unexpected nested elements around your button.
Conclusion
Using asChild
with TooltipTrigger
resolves the issue of unwanted form validation in Shadcn/UI forms. This small but impactful change ensures a smoother user experience and maintains expected form behavior.