next-ssr-form
⚠️⚠️ This is an experimental library and is likely to be discontinued ⚠️⚠️
About
- 🔨 Uses Next.js'
getServerSideProps
to receive post data and provide helpers to the page to render the form - 🎷 E2E type safety! TypeScript types inferred between client & server with all the nice autocomplete jazz
- 🔐 Server-side data validation that's propagated to page props & your
mutation
s' return values are inferred. - ☁️ Allows you to write data straight to the db with confidence
- 🤘 Your page will wors without JS enabled (if you want it to)
(Peer) Dependencies:
- zod for data validation
- Formik as the form library
Table of contents:
Get started
ℹ️ Easiest thing to do is to look at the pages in examples/typescript
.
0. Install
yarn add next-ssr-form zod formik
1. Add form to top of page
In a Next.js page/..
:
export const createPostForm = createForm({
schema: z.object({
from: z.string().min(2),
message: z.string().min(4),
}),
defaultValues: {
message: "",
from: "",
},
formId: "createPost",
});
2. Add mutation to getServerSideProps
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
const createPostProps = await createPostForm.getPageProps({
ctx,
async mutation(input) {
return DB.createPost(input);
},
});
return {
props: {
...createPostProps,
posts: await DB.getAllPosts(),
},
};
};
3. Infer data types
type Props = InferGetServerSidePropsType<typeof getServerSideProps>;
export default function Home(props: Props) {
Your data usage is now typesafe!
4. Use form
Basic form w/o JS
type Props = InferGetServerSidePropsType<typeof getServerSideProps>;
export default function Home(props: Props) {
const [feedback, setFeedback] = useState(
createPostForm.getFeedbackFromProps(props)
);
const initalValues = createPostForm.getInitialValues(props);
const initialErrors = createPostForm.getInitialErrors(props);
return (
<>
<h1>Normal http post (zod for validation)</h1>
<p>
Uses a standard <code><form></code> with the <code>action</code>
-attribute to post to the same page. Form data is handled in{' '}
<code>getServerSideProps</code> and feedback is passed through page
props.
</p>
<h2>My guestbook</h2>
{props.posts.map(item => (
<article key={item.id}>
<strong>
From {item.from} at {item.createdAt}:
</strong>
<p className="message">{item.message}</p>
</article>
))}
<h3>Add post</h3>
<form action={props.createPost.endpoints.action} method="post">
<p className={`field ${initialErrors?.from ? 'field--error' : ''}`}>
<label>
Your name:
<br />
<input type="text" name="from" defaultValue={initalValues.from} />
{initialErrors?.from && (
<span className="field__error">{initialErrors.from}</span>
)}
</label>
</p>
<p className={`field ${initialErrors?.message ? 'field--error' : ''}`}>
<label>
Your message:
<br />
<textarea name="message" defaultValue={initalValues.message} />
{initialErrors?.message && (
<span className="field__error">{initialErrors.message}</span>
)}
</label>
</p>
<input type="submit" />
<br />
{feedback?.state === 'success' && (
<span className="feedback success">Yay! Your entry was added</span>
)}
{feedback?.state === 'error' && (
<>
<span className="feedback error">
Something went wrong: {feedback.error.message}. Full Error:{' '}
<pre>
{JSON.stringify(
{
...feedback.error,
message: feedback.error.message,
stack: feedback.error.stack,
},
null,
4
)}
</pre>
</span>
</>
)}
</form>
</>
);
}
Author
@alexdotjs