Blocks

Form 6

Forms
Text Align Left2 ColumnsForm
Form 6

Code

relume-form6.tsx
"use client";

import { useState } from "react";
import { Button, type ButtonProps } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Mail } from "relume-icons";

type Props = {
  heading: string;
  description: string;
  buttons: ButtonProps[];
};

export type Form6Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;

export const Form6 = (props: Form6Props) => {
  const { heading, description, buttons } = {
    ...Form6Defaults,
    ...props,
  };

  const [firstNameInput, setFirstNameInput] = useState("");
  const [lastNameInput, setLastNameInput] = useState("");
  const [emailInput, setEmailInput] = useState("");
  const [countryInput, setCountryInput] = useState("");
  const [streetAddressInput, setStreetAddressInput] = useState("");
  const [cityInput, setCityInput] = useState("");
  const [stateInput, setStateInput] = useState("");
  const [zipInput, setZipInput] = useState("");

  const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    console.log({
      firstNameInput,
      lastNameInput,
      emailInput,
      countryInput,
      streetAddressInput,
      cityInput,
      stateInput,
      zipInput,
    });
  };

  const selectItems = [
    { value: "first-choice", label: "First Choice" },
    { value: "second-choice", label: "Second Choice" },
    { value: "third-choice", label: "Third Choice" },
  ];

  return (
    <section>
      <div className="grid items-end justify-items-end gap-6 border-b border-scheme-border pb-5 sm:grid-cols-[1fr_max-content] sm:justify-items-start md:pb-6">
        <div className="w-full max-w-lg">
          <h2 className="text-h5 font-bold">{heading}</h2>
          <p className="mt-2">{description}</p>
        </div>
        <div className="flex flex-wrap items-center gap-4">
          {buttons.map((button, index) => (
            <Button key={index} {...button}>
              {button.title}
            </Button>
          ))}
        </div>
      </div>
      <form onSubmit={handleSubmit}>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label htmlFor="firstName" className="mb-2">
            First and last name
          </Label>
          <div className="grid w-full max-w-md gap-4 md:grid-flow-col">
            <Input
              type="text"
              id="firstName"
              placeholder="Enter your first name"
              value={firstNameInput}
              onChange={(e) => setFirstNameInput(e.target.value)}
            />
            <Input
              type="text"
              id="lastName"
              placeholder="Enter your last name"
              value={lastNameInput}
              onChange={(e) => setLastNameInput(e.target.value)}
            />
          </div>
        </div>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label htmlFor="email" className="mb-2">
            Email address
          </Label>
          <div className="w-full max-w-md">
            <Input
              type="email"
              id="email"
              value={emailInput}
              icon={<Mail className="size-6 text-scheme-text" />}
              placeholder="hello@relume.io"
              onChange={(e) => setEmailInput(e.target.value)}
            />
          </div>
        </div>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label className="mb-2">Country</Label>
          <Select onValueChange={setCountryInput}>
            <SelectTrigger className="w-full max-w-md">
              <SelectValue placeholder="Select one..." />
            </SelectTrigger>
            <SelectContent>
              {selectItems.map((item, index) => (
                <SelectItem key={index} value={item.value}>
                  {item.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label htmlFor="street" className="mb-2">
            Street address
          </Label>
          <div className="w-full max-w-md">
            <Input
              type="text"
              id="street"
              placeholder="e.g. 123 Sample St"
              value={streetAddressInput}
              onChange={(e) => setStreetAddressInput(e.target.value)}
            />
          </div>
        </div>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label htmlFor="city" className="mb-2">
            City
          </Label>
          <div className="w-full max-w-md">
            <Input
              type="text"
              id="city"
              placeholder="e.g. Sydney"
              value={cityInput}
              onChange={(e) => setCityInput(e.target.value)}
            />
          </div>
        </div>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label htmlFor="state" className="mb-2">
            State / Province
          </Label>
          <div className="w-full max-w-md">
            <Input
              type="text"
              id="state"
              placeholder="e.g. New South Wales"
              value={stateInput}
              onChange={(e) => setStateInput(e.target.value)}
            />
          </div>
        </div>
        <div className="grid items-start gap-x-12 border-b border-scheme-border py-6 md:grid-cols-[0.5fr_1fr] lg:grid-cols-[0.75fr_1fr]">
          <Label htmlFor="zip" className="mb-2">
            ZIP / Postal code
          </Label>
          <div className="w-full max-w-md">
            <Input
              type="text"
              id="zip"
              placeholder="e.g. 2000"
              value={zipInput}
              onChange={(e) => setZipInput(e.target.value)}
            />
          </div>
        </div>
        <div className="mt-6 flex items-center justify-end gap-4 md:mt-8">
          {buttons.map((button, index) => (
            <Button key={index} {...button}>
              {button.title}
            </Button>
          ))}
        </div>
      </form>
    </section>
  );
};

export const Form6Defaults: Props = {
  heading: "Personal information",
  description:
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.",
  buttons: [
    { title: "Cancel", variant: "secondary", size: "sm" },
    { title: "Save", size: "sm" },
  ],
};

npm i @hookform/resolvers@^3.10.0 @radix-ui/react-label @radix-ui/react-popover @radix-ui/react-select @radix-ui/react-slot class-variance-authority@0.7.1 clsx@^2.1.1 luxon@^3.5.0 react-day-picker@9.5.0 react-hook-form@^7.62.0 relume-icons@1.3.0 tailwind-merge@^2.2.2 zod@^3.24.1