• Blog
  • Documentation
  • Courses
  • Changelog
  • AI Starters
  • UI Kit
  • FAQ
  • Supamode
    New
  • Pricing

Launch your next SaaS in record time with Makerkit, a React SaaS Boilerplate for Next.js and Supabase.

Makerkit is a product of Makerkit Pte Ltd (registered in the Republic of Singapore)Company Registration No: 202407149CFor support or inquiries, please contact us

About
  • FAQ
  • Contact
  • Verify your Discord
  • Consultation
  • Open Source
  • Become an Affiliate
Product
  • Documentation
  • Blog
  • Changelog
  • UI Blocks
  • Figma UI Kit
  • AI SaaS Starters
License
  • Activate License
  • Upgrade License
  • Invite Member
Legal
  • Terms of License
    • Introduction
    • Initial Setup
    • Project Structure
    • Running the App
    • Project Configuration
    • Environment Variables
    • Authentication
    • Onboarding Flow
    • Development: adding custom features
    • Firestore: Data Fetching
    • Firestore: Data Writing
    • Forms
    • Application Pages
    • API Routes
    • API Routes Validation
    • Translations
    • Functions you need to know
    • Adding pages to the Marketing Site
    • Adding Blog Posts
    • Adding Documentation pages
    • Deploying to Production
    • Updating to the latest version

Forms

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
components/tasks/CreateTaskForm.tsx
import { useRouter } from 'next/router';
import { FormEventHandler, useCallback } from 'react';
import { toast } from 'sonner';
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) => {
event.preventDefault();
const target = event.currentTarget;
const data = new FormData(target);
const name = data.get('name') as string;
const dueDate = (data.get('dueDate') as string) || getDefaultDueDate();
setLoading(true);
const task = {
organizationId,
name,
dueDate,
description: ``,
done: false,
};
const promise = createTask(task).then(() => {
return router.push(`/tasks`);
});
await toast.promise(promise, {
success: `Task created!`,
error: `Ops, error!`,
loading: `Creating task...`,
});
},
[router, createTask, organizationId, setLoading]
);
return (
<div className={'flex flex-col space-y-4'}>
<div>
<Heading type={2}>Create a new Task</Heading>
</div>
<form onSubmit={onCreateTask}>
<div className={'flex flex-col space-y-3'}>
<TextField.Label>
Name
<TextField.Input
required
name={'name'}
placeholder={'ex. Launch on IndieHackers'}
/>
<TextField.Hint>Hint: whatever you do, ship!</TextField.Hint>
</TextField.Label>
<TextField.Label>
Due date
<TextField.Input name={'dueDate'} type={'date'} />
</TextField.Label>
<div
className={
'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...
</If>
</Button>
<Button color={'transparent'} href={'/tasks'}>
Go back
</Button>
</div>
</div>
</form>
</div>
);
};
function getDefaultDueDate() {
const date = new Date();
date.setDate(date.getDate() + 1);
date.setHours(23, 59, 59);
return date.toDateString();
}
export default CreateTaskForm;