Next.js Discord

Discord Forum

Form in Accordion(shadcn)

Unanswered
Yellow croaker posted this in #help-forum
Open in Discord
Yellow croakerOP
Hello what i'm trying to accomplish is to have a form inside an accordion. And all the accordions should be listed, so when user click opens one that they have filled earlier it would open with the form in it and the data that they inserted earlier to it. So basically im making resumeBuilder, where user can write their earlier work experience, and there can be multiple work experiences, so thats why i want to list the accordions, that opens to form with the data. I give the form as props for my workExperience component. CvTemplate is used for live preview of user inputs from forms
export default function ResumeBuilder({ resume }: ResumeMakerProps) {
  const form = useForm<formSchemaType>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      personalInfo: {
        name: resume?.personalInfo?.name || defaultFormValues.name,
        email: resume?.personalInfo?.email || defaultFormValues.email,
        phone: resume?.personalInfo?.phone || defaultFormValues.phone,
        address: resume?.personalInfo?.address || defaultFormValues.address,
      },
      workExperience: [],
    },
  });
...
return(
<div>
            <div className="mb-2">
              <WorkExperienceDetail resume={resume} form={form} />
            </div>

      <div>
        <CvTemplate resume={resume} form={form} />
      </div>
</div>
)
}

5 Replies

Yellow croakerOP
const WorkExperienceDetail: React.FC<WorkExperienceInfoProps> = ({
  resume,
  form,
}) => {
  const onSubmit = async (formData: formSchemaType) => {
    mutate({ ...formData }, false);

}

...

return(
<div>
      <Card className="mb-4">
        <CardHeader>
          <CardTitle>Work Experience</CardTitle>
        </CardHeader>
        <CardContent>
          <div className="mb-2">
            {form.getValues('workExperience').map((workExperience, index) => {
              console.log('index', index);
              return (
                <div key={index}>
                  <Accordion type="single" collapsible className="w-full">
                    <AccordionItem value={`item-${index}`}>
                      <AccordionTrigger>is this accessible</AccordionTrigger>
                      <AccordionContent>
                        <div className="grid grid-cols-1 gap-6">
                          <Form {...form}>
                            <form onSubmit={form.handleSubmit(onSubmit)}>
                              {fields.map((field, index) => (
                                <>
                                  <FormField
                                    control={form.control}
                                    key={field.id}
                                    name={`workExperience.${index}.value`}
                                    render={({ field }) => (
<FormItem>
                                        <FormLabel>company</FormLabel>
                                        <FormDescription>
                                          description
                                        </FormDescription>
                                        <FormControl>
                                          <Input
                                            {...form.register(
                                              `workExperience.${index}.company`,
                                            )}
                                          />
                                        </FormControl>
                                        <FormMessage />
                                      </FormItem>
                                    )}
                                  />
                                </>
                              ))}
                              <div className="flex justify-end mt-4">
                                <Button
                                  type="button"
                                  onClick={() => append({ value: '' })}
                                >
                                  Save
                                </Button>
                              </div>
                            </form>
                          </Form>
                        </div>
                      </AccordionContent>
                    </AccordionItem>
                  </Accordion>
                </div>
              );
            })}
          </div>
          <Button type="button" onClick={() => append({ value: '' })}>
            Add Experience
          </Button>
        </CardContent>
        <CardContent>
          <div className="mb-2"></div>
        </CardContent>
        <CardFooter></CardFooter>
      </Card>
    </div>
Yellow croakerOP
So with all this how i should manage the inputs to make it so that user can add new work experiences and the added forms are also showed to them.
Yellow croakerOP
const WorkExperienceDetail: React.FC<WorkExperienceInfoProps> = ({ form }) => {
  const { register, control, handleSubmit, formState } = form;
  const { fields, append, remove } = useFieldArray({
    control,
    name: 'workExperience',
  });
  const onSubmit = (values: any) => {
    console.log('Save work experience');
  };
  return (
    <div>
      <Card>
        <CardContent>
          <h2>Työkokemus</h2>
          {fields.map((field, index) => (
            <div key={field.id}>
              <Accordion type="single" collapsible className="w-full">
                <AccordionItem value={`item-${index}`}>
                  <AccordionTrigger>{field.company}</AccordionTrigger>
                  <AccordionContent>
                    <Form {...form}>
                      <form onSubmit={handleSubmit(onSubmit)}>
                        <Input
                          {...register(`workExperience.${index}.company`)}/>

                        <Input {...register(`workExperience.${index}.role`)} />

                        <AccordionTrigger>
                          {' '}
                          <Button type="submit">Submit</Button>
                        </AccordionTrigger>
                        {index > 0 && (
                          <Button onClick={() => remove(index)}>Remove</Button>
                        )}
                      </form>
                    </Form>
                  </AccordionContent>
                </AccordionItem>
              </Accordion>
            </div>
          ))}
          <Button
            type="button"
            onClick={() => append({ company: '', role: '', active: true })}
          >
            Add Work Experience
          </Button>
        </CardContent>
      </Card>
    </div>
  );
};
These problems i still have.
- All accordions can be opened same time? Single should make them so that only one can be open at a time. (Fixed: Accordion was inside map so they were all unique accordiods)
- submit button doesnt fire onSubmit function(fixed: There were error on formState. In validation i had that some of the fields were required. Problem was that there were no any indication about any errors)
- {field.company} doesnt show data after submit, i have to reload page to actually show the data.
- Is there way to customzie the forms invidiually? im using map so just wondering is it possible. Etc i want start and end date to be on same row.(fixed: Yes it's possible even thought the inputs are mapped, they can still be styled with inline classname attribute)