こんにちは。プロダクト開発部新田です。
今回は小さなスニペットの紹介です。
弊社ではフロントエンドにReact + Typescriptを使用しており、
CSS-in-JSのフレームワークとしてChakra UIを採用することが非常に多いです。
ので以下のコードスニペットは上記の技術構成を前提にしたものです。
ログイン失敗したときにわかりやすくログイン拒否されたことを通知する
ログインエラーをユーザーに通知する典型的な方法いくつか挙げると、
window.alert
単に window.alert
でエラーを表示する方法は実装がかなり容易ですが、荒削りな印象を与えてしまうと思います。
ログインボタン付近に目立つ文字で「ログインエラー」を表示する
この方法は一般的ですが、二度三度ログイン失敗したときのためににすこし気をつけて実装する必要があります。
toast
でエラーを表示する
toast は Androidとかマテリアルデザイン文脈由来のような気がしますが[要出典]、
ポップアップでメッセージを出せて、時間が経つことで/能動的にクリックすることで消えるので便利なシーンが多い印象です。
今回提案する方法
framer-motion でログインボタンを揺らす、という方法とその実装を提案します。
(「首をふる動作に似ているため直感的にエラーがあったことがわかり〜」など、見た目に面白い以上の意味づけをしてもいいんですが、本当の理由は見た目に面白いからです。)
Web上でのアニメーションに慣れていない場合、実装が面倒そうで忌避してしまいがちですが、framer-motionを使うと簡単に実装ができます。
import { chakra } from '@chakra-ui/react'; import { useToast } from '@chakra-ui/toast'; import axios from 'axios'; import { motion, useAnimation } from 'framer-motion'; import React, { useState } from 'react'; export function LoginPageContent() { const [isRequesting, setIsRequesting] = useState(false); const [formState, setFormState] = useState<LoginFormState>(initState); const controls = useAnimation(); const shake = { x: [0, -10, 10, -10, 10, 0], transition: { duration: 0.2 }, }; const onSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); setIsRequesting(true); axios .post('/api/sessions/login', formState) .then(() => { // ログインできた時の処理 }) .catch((e) => { console.error(e); controls.start(shake); }) .finally(() => { setIsRequesting(false); }); }; return ( <chakra.div paddingTop="32px" w="100%"> {isRequesting && <LoadingCover />} <chakra.div bgColor="white" borderRadius="8px" boxShadow="0px 1px 2px 0px rgba(0, 0, 0, 0.06), 0px 1px 3px 0px rgba(0, 0, 0, 0.10);" margin="auto" maxW="90vw" padding="24px" w="750px" > <chakra.h2 color="asBlack" fontSize="24px" fontWeight="bold" textAlign="center"> ログイン画面 </chakra.h2> <chakra.div h="32px" /> <chakra.form margin="auto" maxW="80%" w="300px" onSubmit={onSubmit}> <input id="ログインID" /> <input id="パスワード" /> <chakra.div animate={controls} as={motion.div} display="flex" justifyContent="center" > <RadiusButton kind="blue" type="submit"> ログイン </RadiusButton> </chakra.div> </chakra.form> </chakra.div> </chakra.div> ); }
こうです。
要は
const controls = useAnimation(); const shake = { x: [0, -10, 10, -10, 10, 0], transition: { duration: 0.2 }, };
と
<chakra.div animate={controls} as={motion.div} >
で実装できてしまう、という話でした。
おわりに
エンジニアは正常系に集中してプロダクト開発しがちですが、
実際に計測をしてみると(特にパスワード管理ツールを使っている人には信じがたいほど)ログイン失敗は頻繁に起こっており、
そういった異常系の体験にも気を配るとちょっと熟れたプロダクトに見えるかなと思います。