Learn how to build forms in the Next.js Firebase kit

Now that we have created a custom hook to write data to Firestore, we need to build a form to create a new task.

The example below is straightforward:

  1. We have a form with two input fields
  2. When the form is submitted, we read the data using FormData
  3. Finally, we add the document using the callback returned by the hook useCreateTask
import { useRouter } from 'next/router';
import { FormEventHandler, useCallback } from 'react';
import toaster from 'react-hot-toast';
import TextField from '~/core/ui/TextField';
import Button from '~/core/ui/Button';
import If from '~/core/ui/If';
import Heading from '~/core/ui/Heading';
import useCreateTask from '~/lib/tasks/hooks/use-create-task';
import { useRequestState } from '~/core/hooks/use-request-state';
import { useCurrentOrganization } from '~/lib/organizations/hooks/use-current-organization';
const CreateTaskForm = () => {
  const createTask = useCreateTask();
  const { setLoading, state } = useRequestState();
  const router = useRouter();
  const organization = useCurrentOrganization();
  const organizationId = organization?.id as string;
  const onCreateTask: FormEventHandler<HTMLFormElement> = useCallback(
    async (event) => {
      const target = event.currentTarget;
      const data = new FormData(target);
      const name = data.get('name') as string;
      const dueDate = (data.get('dueDate') as string) || getDefaultDueDate();
      const task = {
        description: ``,
        done: false,
      await toaster.promise(createTask(task), {
        success: `Task created!`,
        error: `Ops, error!`,
        loading: `Creating task...`,
      await router.push(`/tasks`);
    [router, createTask, organizationId, setLoading]
  return (
    <div className={'flex flex-col space-y-4'}>
        <Heading type={2}>Create a new Task</Heading>
      <form onSubmit={onCreateTask}>
        <div className={'flex flex-col space-y-3'}>
              placeholder={'ex. Launch on IndieHackers'}
            <TextField.Hint>Hint: whatever you do, ship!</TextField.Hint>
            Due date
            <TextField.Input name={'dueDate'} type={'date'} />
              'flex flex-col space-y-2 md:space-y-0 md:space-x-2' +
              ' md:flex-row'
            <Button loading={state.loading}>
              <If condition={state.loading} fallback={<>Create Task</>}>
                Creating Task...
            <Button color={'transparent'} href={'/tasks'}>
              Go back
function getDefaultDueDate() {
  const date = new Date();
  date.setDate(date.getDate() + 1);
  date.setHours(23, 59, 59);
  return date.toDateString();
export default CreateTaskForm;

Subscribe to our Newsletter
Get the latest updates about React, Remix, Next.js, Firebase, Supabase and Tailwind CSS