Search code examples
javascriptreactjsshadcnui

React Shadcn TextArea with Chips


I'm using React, React-Hook-Form, Zod and Shadcn-ui. My problem is that i wanted to enter multiples names in the textarea, once you put a comma on it, it will be converted like a chip(https://mui.com/material-ui/react-chip/), and then you'll be able to enter another name and so on.

The chips can also be deleted individually.

Expected output when submitting are just names with comma.

CODESANDBOX ----> CLICK HERE

CODE

   <Form {...form}>
      <form
        onSubmit={form.handleSubmit(onSubmit)}
        method="post"
        className="space-y-8"
      >
        <FormField
          control={form.control}
          name="names"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Names</FormLabel>
              <FormControl>
                <Textarea placeholder="shadcn" {...field} />
              </FormControl>
              <FormDescription>
                Enter names separated by a comma
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>

Solution

  • Replace your code with:

    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(onSubmit)}
        method="post"
        className="space-y-8"
      >
        <FormField
          control={form.control}
          name="names"
          render={({ field: { value, onChange } }) => (
            <FormItem>
              <FormLabel>Names</FormLabel>
              <div className="p-2 border rounded-md border-input">
                <div className="flex gap-2 empty:hidden">
                  {!!value.trim().length &&
                    value?.split(",").map((name, index) => (
                      <div
                        key={index}
                        className="rounded-md inline-flex items-center pl-2.5 py-1 pr-1 text-xs bg-zinc-100"
                      >
                        {name}
                        <button
                          type="button"
                          onClick={() =>
                            onChange(
                              value
                                .split(",")
                                .filter((_) => _ != name)
                                .join(",")
                            )
                          }
                        >
                          <svg
                            width="12"
                            height="12"
                            viewBox="0 0 15 15"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                            className="ml-2"
                          >
                            <path
                              d="M12.8536 2.85355C13.0488 2.65829 13.0488 2.34171 12.8536 2.14645C12.6583 1.95118 12.3417 1.95118 12.1464 2.14645L7.5 6.79289L2.85355 2.14645C2.65829 1.95118 2.34171 1.95118 2.14645 2.14645C1.95118 2.34171 1.95118 2.65829 2.14645 2.85355L6.79289 7.5L2.14645 12.1464C1.95118 12.3417 1.95118 12.6583 2.14645 12.8536C2.34171 13.0488 2.65829 13.0488 2.85355 12.8536L7.5 8.20711L12.1464 12.8536C12.3417 13.0488 12.6583 13.0488 12.8536 12.8536C13.0488 12.6583 13.0488 12.3417 12.8536 12.1464L8.20711 7.5L12.8536 2.85355Z"
                              fill="currentColor"
                              fillRule="evenodd"
                              clipRule="evenodd"
                            ></path>
                          </svg>
                        </button>
                      </div>
                    ))}
                </div>
                <FormControl>
                  <Textarea
                    placeholder="Enter names"
                    className="min-h-40 border-0 focus-visible:ring-0"
                    onKeyDown={(e) => {
                      if (e.key == ",") {
                        if (!value) {
                          onChange(e.target.value.replace(",", ""));
                          e.target.value = ""; // clear the textarea value
                        } else {
                          onChange(
                            value.concat(",", e.target.value.replace(",", ""))
                          );
                          e.target.value = "";
                        }
                        e.preventDefault(); // do not let comma ',' to enter in textarea
                      }
                    }}
                  />
                </FormControl>
              </div>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>