Skip to content

Commit 1a2f722

Browse files
committed
update README, package.json, and TypeScript types; enhance form handling and validation
1 parent 35dc25c commit 1a2f722

7 files changed

Lines changed: 235 additions & 128 deletions

File tree

README.md

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,137 @@
1-
21
# Formbold-react — The easiest way to configure and use Form in React/Next.js
32
React package for [FormBold](https://formbold.com/) which simplifies the integration of FormBold with React/Next.js projects.
43

54
FormBold is a multipurpose form API and serverless backend solution compatible with all hosting, SSG, and frameworks. It allows you to receive form submissions directly in your email, slack, telegram, notion, and more. It's ready for use with any Static, Jamstack, and SSG sites, such as HTML, React, Next.js, Gatsby, Vue, Nuxt, Hugo, and Jekyll.
65

76
It offers a wide range of form fields, advanced features like conditional logic, and seamless integration with other tools.
87

8+
It helps you wire a form to FormBold with a small API, built-in validation for required fields, custom error messages, and basic submission state.
9+
910
## Installation
1011

1112
```bash
1213
npm install formbold-react
1314
```
1415

15-
or
16-
1716
```bash
1817
yarn add formbold-react
1918
```
2019

21-
## Usages
22-
23-
To use it you have to import it in your Form component. Then call it with the form_id.
20+
## Usage
2421

25-
And at the end, attach the handleSubmit function to the onSubmit event.
22+
Import `useForm`, pass your FormBold `formId`, and attach the returned `handleSubmit` function to your form.
2623

27-
```typescript
24+
```tsx
2825
import { useForm } from "formbold-react";
2926

30-
function Form() {
27+
function ContactForm() {
3128
const [state, handleSubmit] = useForm("form_id");
3229

3330
if (state.succeeded) {
34-
return <div>Form submitted successfully</div>;
31+
return <div>Form submitted successfully.</div>;
3532
}
3633

3734
return (
38-
<>
39-
<h1>Home Page</h1>
40-
<form onSubmit={handleSubmit}>
41-
<label htmlFor="email">Email Address</label>
42-
<input id="email" type="email" name="email" required />
43-
<textarea id="message" name="message" required />
44-
<button type="submit">{state.submitting ? "Submitting..." : "Submit"}</button>
45-
46-
<div>
47-
{state.error && state.error.message}
48-
</div>
49-
</form>
50-
</>
35+
<form onSubmit={handleSubmit}>
36+
<label htmlFor="email">Email Address</label>
37+
<input id="email" type="email" name="email" required />
38+
39+
<label htmlFor="message">Message</label>
40+
<textarea id="message" name="message" required />
41+
42+
<button type="submit">
43+
{state.submitting ? "Submitting..." : "Submit"}
44+
</button>
45+
46+
{state.error.status && <p>{state.error.message}</p>}
47+
</form>
5148
);
5249
}
5350

54-
export default Form;
51+
export default ContactForm;
5552
```
5653

57-
## Required fields
54+
## API
5855

59-
To make certain fields mandatory in your form, you can use the `requiredFields` option when using the `useForm` hook. In the example below, the `email` field is set as a required field:
56+
### `useForm(formId, config?)`
6057

61-
```typescript
62-
const [state, handleSubmit] = useForm("form_id", { requiredFields: ["email"] });
58+
```ts
59+
const [state, handleSubmit] = useForm("form_id", config);
6360
```
64-
This ensures that the form cannot be submitted unless the `email` field is filled out by the user.
6561

62+
Returns:
63+
64+
```ts
65+
[
66+
{
67+
error: { message: string; status: boolean };
68+
succeeded: boolean;
69+
submitting: boolean;
70+
},
71+
(event, recaptchaRef?) => void
72+
]
73+
```
74+
75+
### `config`
6676

67-
## Custom error messages
68-
You can customize the error messages displayed when certain fields are not filled out in your form. By using the `errorMessages` option in the `useForm` hook, you can provide custom error messages for different scenarios.
77+
```ts
78+
type Config = {
79+
requiredFields?: string[];
80+
errorMessages?: {
81+
empty?: string;
82+
required?: (fields: string[]) => string;
83+
};
84+
};
85+
```
6986

70-
Here's an example of how you can set custom error messages for the `name` and `email` fields:
87+
Example:
7188

72-
```typescript
89+
```ts
7390
const [state, handleSubmit] = useForm("form_id", {
7491
requiredFields: ["name", "email"],
7592
errorMessages: {
7693
empty: "Please fill the form!",
7794
required: fields => `Please fill the required fields: ${fields.join(", ")}`,
78-
}
95+
},
96+
});
97+
```
98+
99+
### Required fields
100+
101+
Use `requiredFields` when you want the hook to block submission until specific inputs are filled.
102+
103+
```ts
104+
const [state, handleSubmit] = useForm("form_id", {
105+
requiredFields: ["email"],
79106
});
80107
```
81108

82-
Feel free to customize the error messages according to your specific requirements.
109+
### reCAPTCHA support
110+
111+
If you use reCAPTCHA, pass the ref as the second argument to the submit handler.
112+
113+
```tsx
114+
<form onSubmit={e => handleSubmit(e, recaptchaRef)}>
115+
```
83116

117+
The hook will include `g-recaptcha-response` in the submitted payload when a ref is provided.
118+
119+
## Behavior notes
120+
121+
- Empty forms are rejected before the request is sent.
122+
- Required field validation runs before submission.
123+
- Non-2xx responses are treated as submission failures.
124+
- Repeated form fields are preserved as arrays in the request payload.
125+
126+
## Types
127+
128+
The package exports its public types from the root entry point:
129+
130+
```ts
131+
import type { Config, ErrorState, CaptchaRef } from "formbold-react";
132+
```
84133

85-
## ****Useful Links and Information****
134+
## Links
86135

87-
For more information visit the [documentation](https://formbold.com/docs).
136+
- [FormBold docs](https://formbold.com/docs)
137+
- [FormBold homepage](https://formbold.com/)

package.json

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
22
"name": "formbold-react",
3-
"version": "1.1.2",
3+
"version": "1.1.3",
44
"description": "Formbold package for react.",
5-
"main": "dist/index.js",
6-
"types": "./dist/index.ts",
5+
"main": "./dist/index.js",
6+
"types": "./dist/index.d.ts",
77
"exports": {
8-
"types": "./dist/index.d.ts",
9-
"default": "./dist/index.js"
8+
".": {
9+
"types": "./dist/index.d.ts",
10+
"default": "./dist/index.js"
11+
}
1012
},
1113
"repository": {
1214
"type": "git",
@@ -17,6 +19,11 @@
1719
"scripts": {
1820
"build": "tsc --declaration"
1921
},
22+
"files": [
23+
"dist",
24+
"README.md",
25+
"LICENSE.md"
26+
],
2027
"license": "MIT",
2128
"keywords": [
2229
"forms",
@@ -28,13 +35,11 @@
2835
"formbold"
2936
],
3037
"devDependencies": {
31-
"@types/react-dom": "^19.2.3",
38+
"@types/react": "^19.0.0",
3239
"typescript": "^5.8.2"
3340
},
3441
"peerDependencies": {
35-
"@types/react": "^19.0.0",
36-
"react": "^19.2.6",
37-
"react-dom": "^19.2.6"
42+
"react": "^18.0.0 || ^19.0.0"
3843
},
3944
"bugs": {
4045
"url": "https://github.com/FormBold/formbold-react/issues"

src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
export { useForm } from "./useForm";
2+
export type {
3+
CaptchaRef,
4+
Config,
5+
DeepRequired,
6+
ErrorMessages,
7+
ErrorState,
8+
FormValues,
9+
} from "./types";

src/types.ts

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,59 @@
22
* Error state for the useForm hook.
33
*/
44
export type ErrorState = {
5-
/** The error message */
6-
message: string;
7-
/** The error status */
8-
status: boolean;
9-
};
10-
5+
/** The error message */
6+
message: string;
7+
/** The error status */
8+
status: boolean;
9+
};
10+
11+
/**
12+
* Error messages for the useForm hook.
13+
*/
14+
export type ErrorMessages = {
15+
/** Error message when the form is empty */
16+
empty?: string;
17+
/** Error message when the required fields are empty */
18+
required?: (fields: string[]) => string;
19+
};
20+
21+
/**
22+
* Configuration options for the useForm hook.
23+
*/
24+
export type Config = {
1125
/**
12-
* Error messages for the useForm hook.
26+
* Custom error messages
27+
*
28+
* @example
29+
* errorMessages: {
30+
* empty: 'Oops the form is empty!',
31+
* required: fields => `You missed: ${fields.join(', ')}`,
32+
* }
1333
*/
14-
export type ErrorMessages = {
15-
/** Error message when the form is empty */
16-
empty?: string;
17-
/** Error message when the required fields are empty */
18-
required?: (fields: string[]) => string;
19-
};
20-
34+
errorMessages?: ErrorMessages;
2135
/**
22-
* Configuration options for the useForm hook.
36+
* List of required fields (by name) that must be filled before submitting the form.
37+
* @default []
38+
*
39+
* @example
40+
* requiredFields: ['name', 'email']
2341
*/
24-
export type Config = {
25-
/**
26-
* Custom error messages
27-
*
28-
* @example
29-
* errorMessages: {
30-
* empty: 'Oops the form is empty!',
31-
* required: fields => `You missed: ${fields.join(', ')}`,
32-
* }
33-
*/
34-
errorMessages?: ErrorMessages;
35-
/**
36-
* List of required fields (by name) that must be filled before submitting the form.
37-
* @default []
38-
*
39-
* @example
40-
* requiredFields: ['name', 'email']
41-
*/
42-
requiredFields?: string[];
42+
requiredFields?: string[];
43+
};
44+
45+
export type DeepRequired<T> = T extends (...args: any[]) => any
46+
? T
47+
: T extends object
48+
? {
49+
[K in keyof T]-?: DeepRequired<T[K]>;
50+
}
51+
: T;
52+
53+
export type CaptchaRef = {
54+
current: {
55+
getValue: () => string;
4356
};
57+
};
58+
59+
export type FormValues = Record<string, FormDataEntryValue | FormDataEntryValue[]>;
4460

45-
export type DeepRequired<T> = Required<{
46-
[K in keyof T]: T[K] extends Required<T[K]> ? T[K] : DeepRequired<T[K]>;
47-
}>;
48-
49-
export type CaptchaRef = { current: { getValue: () => any } };
50-

0 commit comments

Comments
 (0)