@hilma/forms v2.9.0
Hilma Forms
Table of Contents
Overview
@hilma/forms
is a React component library available via npm
which makes writing, validating, and styling forms as easy as possible. It is built on formik
, yup
and mui
.
Getting Started
Installation
To install, run
npm install --save @hilma/forms
Configuration
We recommend wrapping your app with the CSSPrioritize
component. If you do, your css files will have priority over Forms and mui
, and you can override any of our/their styles (without using !important
😉).
index.tsx
:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { CSSPrioritize } from '@hilma/forms';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<CSSPrioritize>
<App />
</CSSPrioritize>
</React.StrictMode>
);
Writing A Basic Form
To write a @hilma/forms
form, we must use the FormProvider
component (API here).
FormProvider
requires two props: initialValues
and onSubmit
.
initialValues
is an object with the starting values of all the fields whose state will be tracked in the form.
onSubmit
is a function that is called with the current values when the user submits the form without any errors.
import { FormProvider } from '@hilma/forms';
const MyForm: React.FC = () => {
return (
<FormProvider
initialValues={{
username: "",
password: ""
}}
onSubmit={(values) => alert(JSON.stringify(values, null, 2))}
>
</FormProvider>
)
}
export default MyForm;
Great! Now we have a useable form. All we need is to fill it with fields.
Every field component in the Forms package takes a required name
prop. This prop should be the same as one of the fields in the initial values of FormProvider
.
So, since our initial values' fields are username
and password
, we should use two field components - one with name="username"
and one with name="password"
.
Since we're dealing with strings, lets use FormTextInput
(API here):
import { FormProvider, FormTextInput } from '@hilma/forms';
const MyForm: React.FC = () => {
return (
<FormProvider
initialValues={{
username: "",
password: ""
}}
onSubmit={(values) => alert(JSON.stringify(values, null, 2))}
>
<FormTextInput name="username" label="Enter your username:" />
<FormTextInput
name="password"
type="password"
label="Enter your password:"
/>
</FormProvider>
)
}
export default MyForm;
Now we already have a form with two fully stylized fields, whose state is being managed by FormProvider
!
But as you may notice, we are missing a way to submit...
Any button
with type="submit"
will do, but Forms exports a FormSubmitButton
(API here) that's already styled:
import { FormProvider, FormTextInput, FormSubmitButton } from '@hilma/forms';
const MyForm: React.FC = () => {
return (
<FormProvider
initialValues={{
username: "",
password: ""
}}
onSubmit={(values) => alert(JSON.stringify(values, null, 2))}
>
<FormTextInput name="username" label="Enter your username:" />
<FormTextInput
name="password"
type="password"
label="Enter your password:"
/>
<FormSubmitButton>Submit</FormSubmitButton>
</FormProvider>
)
}
export default MyForm;
Form-tastic! Now when we fill in the fields and press Submit
we'll get an alert with something like
{
"username": "Bret",
"password": "3159"
}
thanks to our onSubmit
!
Styling A Form
About Styling
Forms components, along with being functional and useful, are also pre-styled. We have spent time and effort ensuring that each component is objectively beautiful.
We are, however, aware that no style is one-size-fits-all, so we provide several methods to change and override the default Forms styling. Some of these methods are global and application-wide, and some are component-specific. We list each method in the sections below.
Every single one of @hilma/forms
's styling methods is designed to be simple and accessible. If you're attempting to apply your own styling to Forms components and it seems hard or unintuitive - you're probably not doing it the intended way.
Variants (Rounded VS Squircle)
By default, every Forms component is styled in an almost-square way, with slightly rounded corners. This works for most designs, but sometimes you need something a little more round or pill-shaped. For this, most Forms field components take a rounded
prop, which will apply a rounder, more "pill-shaped" design.
const MyForm: React.FC = () => {
return (
<FormProvider initialValues={{ mood: "" }} onSubmit={...}>
<FormTextInput
rounded
name="mood"
/>
</FormProvider>
)
}
MUI Theme
Forms is built on MUI, so every Forms component will respond to your MUI theme. You can find out which theme values are used by which Forms components in their API documentation.
Let's take a look at how we can turn all of our Forms components' error messages to green:
index.tsx
:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { CSSPrioritize } from '@hilma/forms';
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
palette: {
error: {
main: "green",
}
}
});
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<CSSPrioritize>
<App />
</CSSPrioritize>
</ThemeProvider>
</React.StrictMode>
);
Forms Classnames
Note: this is the recommended way to stylize @hilma/forms
.
Most often when customizing Forms components, we want to create our own unique styling, but keep it consistent across our application.
Every Forms component, component section and status effect (!implement) have an associated classname or classnames. These can be used in CSS and SASS/SCSS files to stylize the component to your choosing. If you want your styles to override those of Forms, you need to import CSSPrioritize
as explained above.
These classnames are listed in each component's API reference below.
Let's take a look at how we could customize a FormTextInput
using these classnames:
In our .tsx
file:
const MyStyledForm: React.FC = () => {
return (
<FormProvider initialValues={{ feedback: "" }} onSubmit={...}>
<FormTextInput name="feedback" />
</FormProvider>
)
}
In a .css
or .scss
file:
.Form-textInput {
width: 100%;
border: 'green';
}
.Form-textInput-errorMsg {
font-size: 24px;
}
If we want to get more specific, we can pass any Forms component the containerClassName
prop, which allows us to specify which instance of the component we want. (Note that className
is passed to the root component and not to the container, so we can't use it for parent-child specificity).
In our .tsx
file:
const MyStyledForm: React.FC = () => {
return (
<FormProvider
initialValues={{ thingOne: "", thingTwo: "" }}
onSubmit={...}
>
<FormTextInput
name="thingOne"
containerClassName="thing-one"
/>
<FormTextInput
name="thingTwo"
containerClassName="thing-two"
/>
</FormProvider>
)
}
In a .scss
file:
.thing-one {
& .Form-textInput {
color: yellow;
}
}
.thing-two {
& .Form-textInput {
color: red;
}
}
(Note that this can also be achieved with a .css
file but it is more verbose).
Props (sx
, classes
, className
and more)
(Read more about root components)
The default MUI styling props that are given to a Forms component are passed to its root component. This includes sx
, classes
, and classname
. Additional props are listed in each component's API reference.
Let's take a look at giving the MuiInput
inside of FormTextInput
a purple background using sx
.
const MyStyledForm: React.FC = () => {
return (
<FormProvider initialValues={{ item: "" }} onSubmit={...}>
<FormTextInput
name="item"
sx={{ backgroundColor: "purple" }}
/>
</FormProvider>
)
}
Validating A Form
Forms is built on Formik, which uses Yup for validation. Yup is an easy-to-use and easy-to-read validation library, so Forms uses it as well.
(Note: we plan on releasing custom, pre-prepared Yup schemas in the future, but for now, you'll have to write them on your own)
Yup exports a bunch of functions named like basic JavaScript types (object, string, etc), which we chain to create schemas - objects that we can use for validation.
For example, if we have a field that we want to be a required string with at least three characters:
import { string } from 'yup';
const fieldSchema = string().required().min(3);
Now we have a useable Yup schema, which will return a pre-built error message if incorrect, when validated. If we want to use our own error messages:
import { string } from 'yup';
const fieldSchema = string()
.required("You have to fill me in!")
.min(3, "I must be three characters or more");
Important note: in the examples above we imported Yup's string
function on its own, but we don't want to do this: it's confusing and not very readable. Instead, we'll do:
import * as yup from 'yup';
const fieldSchema = yup.string().required(...) // etc.
(Since we use Babel for our projects, it will minimize the import size anyway, so it's not a concern)
Until now we have discussed what it's like to use Yup generally, but let's see how we would use it with Forms. First, let's build a schema:
import * as yup from 'yup';
const formSchema = yup.object({
firstName: yup.string().required("You must have a name!");
});
Then, let's build our component:
import React from 'react';
import { FormProvider, FormTextInput, FormSubmitButton } from '@hilma/forms';
const MyForm: React.FC = () => {
return (
<FormProvider
initialValues={{ firstName: "" }}
onSubmit={...}
>
<FormTextInput name="firstName" label="Enter your name:" />
<FormSubmitButton>Submit</FormSubmitButton>
</FormProvider>
);
}
Finally, let's use FormProvider
's validationSchema
prop to put them together:
import React from 'react';
import { FormProvider, FormTextInput, FormSubmitButton } from '@hilma/forms';
import * as yup from 'yup';
const formSchema = yup.object({
firstName: yup.string().required("You must have a name!")
})
const MyForm: React.FC = () => {
return (
<FormProvider
initialValues={{ firstName: "" }}
onSubmit={...}
validationSchema={formSchema}
>
<FormTextInput name="firstName" label="Enter your name:" />
<FormSubmitButton>Submit</FormSubmitButton>
</FormProvider>
);
}
That's it! We now have a fully-functioning form, which will validate itself! If we try to press Submit
while firstName
is still empty, our onSubmit
won't trigger, and instead we'll get a red error message that says "You must have a name!"
. It's really that easy!
Yup has many more useful methods and functions, and we recommend reading about them in the yup docs.
API
FormProvider
FormTextInput
FormSubmitButton
Useful Links
The MUI docs - here
The Yup docs - the README here
The Formik docs - here
5 months ago
5 months ago
5 months ago
5 months ago
10 months ago
6 months ago
5 months ago
10 months ago
10 months ago
6 months ago
6 months ago
10 months ago
10 months ago
10 months ago
10 months ago
5 months ago
6 months ago
6 months ago
8 months ago
7 months ago
5 months ago
10 months ago
6 months ago
6 months ago
7 months ago
8 months ago
10 months ago
7 months ago
7 months ago
5 months ago
6 months ago
6 months ago
10 months ago
5 months ago
7 months ago
5 months ago
10 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago
11 months ago
11 months ago
1 year ago
1 year ago
11 months ago
12 months ago
12 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago