個人開発でUIライブラリを使っていこうかなーと思い探していたところ、Mantineというライブラリを知りました。今回は、MantineのコンポーネントとMantineから提供されているuse-formというAPIを使って簡単な新規登録フォームを作っていきます。なお、具体的な認証機能は実装しません。
Mantineとは?
emotionとtypescriptをベースに作られたMUIやChakra UIのようなUIライブラリです。100を超えるコンポーネントと様々なHooksが利用できます。
以下、私が良いと思った点をまとめておきます。
公式ドキュメントが優秀
- 検索機能が付いていて見たい情報に素早くアクセスできる
- コンポーネントによってはドキュメント上で操作するだけで指定したスタイルのソースコードを生成できるものがある
- 使用例が豊富!
Hooks/APIが豊富
- HooksやAPIが豊富なのでMantineだけでいろいろやりやすい
- React Hook FormのようなフォームコントロールAPIも存在(今回使用するuse-form)
use-fromとは
React Hook FormのようなMantine用のフォーム管理APIです。バリデーションなどもしっかり行うことができます。以下では、このAPIを利用してログインフォームを作っていきます。
Mantineのインストール
はじめに、公式ドキュメントのGetting startedに従って初期設定を行います。(ドキュメントがすごく分かりやすいので説明は不要かもですが・・)
まずは必要なパッケージをインストールします。
npm install @mantine/core @mantine/hooks @mantine/form @emotion/react
次に、ルートコンポーネント(App)をMantineProviderでラップしてあげます。
import { MantineProvider } from "@mantine/core";
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<MantineProvider withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
</React.StrictMode>
);
これで初期設定は終わりなので、最後にButtonコンポーネントを呼び出してみましょう。
import { Button } from "@mantine/core";
function App() {
return <Button>Click me!</Button>;
}
export default App;
こんな感じの良さげなボタンが表示されればOKです。

新規登録フォームをつくる
見た目の作成
初期設定が終わったので、まずMantineのコンポーネントを使用してフォームの見た目をサクっと作っていきましょう。解説は省きます。
import {
TextInput,
Paper,
Container,
Title,
PasswordInput,
Button,
} from "@mantine/core";
const AuthForm = () => {
return (
<Container size={400} my={40}>
<Title align="center" color="cyan.9">
新規登録
</Title>
<Paper p="xl" mx="auto" my="lg" withBorder>
<form>
<TextInput
withAsterisk
label="メールアドレス"
placeholder="xxx@example.com"
/>
<PasswordInput
withAsterisk
label="パスワード"
placeholder="●●●●●●"
mt="md"
/>
<PasswordInput
withAsterisk
label="パスワードの確認"
placeholder="●●●●●●"
mt="md"
/>
<Button type="submit" color="cyan.6" mt="xl" fullWidth>
新規登録
</Button>
</form>
</Paper>
</Container>
);
};
export default AuthForm;
Mantineを使うのは今回が初めてだったんですが、公式ドキュメントが優秀なおかげでスムーズにいい感じのフォームが作れました。

use-formを導入する
まずは、use-formでフォームを管理できるように設定します。
import { useForm } from "@mantine/form";
const AuthForm = () => {
const form = useForm({
initialValues: {
email: "",
password: "",
},
});
まず、useFormをimportし、それを呼び出しておきます。useFormでは、引数としてinitialValuesやvalidate等を設定できますが、バリデーションはのちほど設定するので、まずはinitialValuesのみ設定します。こちらのプロパティでは、各フォームの初期値を設定することができます。
今回はメールアドレス、パスワード、パスワードの確認の3つのフォームを用いるため、initialValuesとしてemail、password、confirmPasswordの3つを設定します。なお、ここで設定したプロパティ名はpathとして利用します。
次に、各inputをuse-formで管理できるように設定します。
<TextInput
withAsterisk
label="メールアドレス"
placeholder="xxx@example.com"
{...form.getInputProps("email")}
/>
<PasswordInput
withAsterisk
label="パスワード"
placeholder="●●●●●●"
mt="md"
{...form.getInputProps("password")}
/>
<PasswordInput
withAsterisk
label="パスワードの確認"
placeholder="●●●●●●"
mt="md"
{...form.getInputProps("confirmPassword")}
/>
各フォームにuse-formのgetInputPropsで返ってくるオブジェクトを展開して渡してあげます。getInputPropsでは、引数として対応するpath(initialValuesで設定したプロパティ名)を指定します。これで各フォームをuse-formで管理できるようになります。
なぜこれで管理できるようになるかというと、getInputPropsでは指定したpathに対応したvalue、onChange、error等を含むオブジェクトが返されるためです。これを展開して各フォームのpropsに指定することで、use-form側でフォームのvalueやerror等を管理できるようになります。
最後に、フォームの値を管理できているのかをチェックしましょう。
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<TextInput
withAsterisk
label="メールアドレス"
placeholder="xxx@example.com"
{...form.getInputProps("email")}
/>
<PasswordInput
withAsterisk
label="パスワード"
placeholder="●●●●●●"
mt="md"
{...form.getInputProps("password")}
/>
<PasswordInput
withAsterisk
label="パスワードの確認"
placeholder="●●●●●●"
mt="md"
{...form.getInputProps("confirmPassword")}
/>
<Button type="submit" color="cyan.6" mt="xl" fullWidth>
新規登録
</Button>
</form>
formのonSubmitには、use-formのonSubmitでラップした関数を渡してあげます。このときのvaluesには、すべてのフォームの値が含まれています。なお、今回は、的な認証機能は実装しないため、コンソールにvaluesを表示させるだけにしています。
あとはフォームを送信し、以下のように入力した値を含むオブジェクトがコンソールに表示されればOKです。

バリデーションを導入する
フォーム作成の締めとして、最後にバリデーションを導入していきます。
const AuthForm = () => {
const form = useForm({
initialValues: {
email: "",
password: "",
confirmPassword: "",
},
validate: {
email: (value) =>
/^\S+@\S+$/.test(value)
? null
: "正しいメールアドレスを入力してください",
password: (value) =>
value.length < 6 ? "6文字以上のパスワードを入力してください" : null,
confirmPassword: (value, values) =>
value !== values.password ? "パスワードが一致していません" : null,
},
});
バリデーションを導入するためには、useFormの引数にvalidateプロパティを追加し、そこにルールオブジェクトを設定します。
ルールオブジェクトでは、プロパティ(email、passwordなど)に対して、フォームの値を引数とした関数を設定してあげましょう。なお、この関数の戻り値には、エラーメッセージ、もしくはnull(正しい場合)を設定しましょう。
また、引数にはプロパティに対応したフォームの値であるvalueのほかに、すべてのフォームの値が入っているvaluesも与えることが出来ます。そのため、上記のコードのconfirmPasswordのバリデーションのように、他のフォームの値を用いたバリデーションを行うことも可能です。
以上でバリデーションの設定は完了です。バリデーションで弾かれている画像を以下に載せておきます。

最後に、今回作成したフォームの全ソースコードを記載しておきます。
import {
TextInput,
Paper,
Container,
Title,
PasswordInput,
Button,
} from "@mantine/core";
import { useForm } from "@mantine/form";
const AuthForm = () => {
const form = useForm({
initialValues: {
email: "",
password: "",
confirmPassword: "",
},
validate: {
email: (value) =>
/^\S+@\S+$/.test(value)
? null
: "正しいメールアドレスを入力してください",
password: (value) =>
value.length < 6 ? "6文字以上のパスワードを入力してください" : null,
confirmPassword: (value, values) =>
value !== values.password ? "パスワードが一致していません" : null,
},
});
return (
<Container size={400} my={40}>
<Title align="center" color="cyan.9">
新規登録
</Title>
<Paper p="xl" mx="auto" my="lg" withBorder>
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<TextInput
withAsterisk
label="メールアドレス"
placeholder="xxx@example.com"
{...form.getInputProps("email")}
/>
<PasswordInput
withAsterisk
label="パスワード"
placeholder="●●●●●●"
mt="md"
{...form.getInputProps("password")}
/>
<PasswordInput
withAsterisk
label="パスワードの確認"
placeholder="●●●●●●"
mt="md"
{...form.getInputProps("confirmPassword")}
/>
<Button type="submit" color="cyan.6" mt="xl" fullWidth>
新規登録
</Button>
</form>
</Paper>
</Container>
);
};
export default AuthForm;
まとめ
今回は、Mantineをフル活用して新規登録フォームを作成しました。使い心地はかなりよかったので、これからは個人開発でも利用していきたいと思います。あと、現状ではMantineに関する日本語の記事がとても少ないので、増えてくれれば大変ありがたいなと思います。