Open Benjamin-Lee opened 1 year ago
This is great @Benjamin-Lee! Thank you so much for contributing 😀
I've had more people asking for better forms support, but haven't had a chance to look into it yet. And to be honest it might still be a few days/weeks/years until I do.
Happy to help. I ended up changing my strategy for doing this to something so much easier: using cva
and just pulling the styles out into an input variant along with some other form-related styles into a file:
import { cva } from "class-variance-authority"
import { cn } from "src/lib/utils"
export const inputVariants = cva(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
)
export const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
{
variants: {
error: {
true: "text-destructive",
},
},
}
)
export const fieldErrorVariants = cva(
"block text-[0.8rem] font-medium text-destructive"
)
export const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
return <div ref={ref} className={cn("space-y-2", className)} {...props} />
})
FormItem.displayName = "FormItem"
Then, building a form is as easy as:
<Form onSubmit={onSubmit} className="space-y-6">
<div className="flex justify-between">
<FormItem>
<Label
name="email"
className={labelVariants()}
errorClassName={labelVariants({ error: true })}
>
First Name
</Label>
<TextField
name="firstName"
className={inputVariants()}
validation={{
required: {
value: true,
message: 'First name is required',
},
}}
autoComplete="given-name"
/>
<FieldError name="firstName" className={fieldErrorVariants()} />
</FormItem>
<FormItem>
<Label
name="lastName"
className={labelVariants()}
errorClassName={labelVariants({ error: true })}
>
Last Name
</Label>
<TextField
name="lastName"
className={inputVariants()}
validation={{
required: {
value: true,
message: 'Last name is required',
},
}}
autoComplete="family-name"
/>
<FieldError name="email" className={fieldErrorVariants()} />
</FormItem>
</div>
<FormItem>
<Label
name="email"
className={labelVariants()}
errorClassName={labelVariants({ error: true })}
>
Email address
</Label>
<EmailField
name="email"
className={inputVariants()}
ref={emailRef}
validation={{
required: {
value: true,
message: 'Email is required',
},
}}
/>
<FieldError name="email" className={fieldErrorVariants()} />
</FormItem>
<FormItem>
<Label
name="password"
className={labelVariants()}
errorClassName={labelVariants({ error: true })}
>
Password
</Label>
<PasswordField
name="password"
className={inputVariants()}
autoComplete="current-password"
validation={{
required: {
value: true,
message: 'Password is required',
},
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
}}
/>
<FieldError name="password" className={fieldErrorVariants()} />
</FormItem>
<div>
<Submit className={cn(buttonVariants(), 'w-full')}>Login</Submit>
</div>
</Form>
I'm trying to use shadcn/ui inside a Redwood project while also using Redwood Forms. It would be great if there were a way for the
<Input>
component from shadcn/ui to wrap the Redwood<TextField>
and its siblings. Here's my first pass at it if it's of any help: