Improve browser autofill

This commit is contained in:
garronej 2022-03-30 16:20:14 +02:00
parent ff19ab8b08
commit 7f5a9e77de

View File

@ -5,6 +5,7 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage"; import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react"; import { useCssAndCx } from "tss-react";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import type { FormEventHandler } from "react";
export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => { export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => {
const { social, realm, url, usernameEditDisabled, login, auth, registrationDisabled } = kcContext; const { social, realm, url, usernameEditDisabled, login, auth, registrationDisabled } = kcContext;
@ -15,7 +16,19 @@ export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.L
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
const onSubmit = useConstCallback(() => (setIsLoginButtonDisabled(true), true)); const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => {
e.preventDefault();
setIsLoginButtonDisabled(true);
const formElement = e.target as HTMLFormElement;
//NOTE: Even if we login with email Keycloak expect username and password in
//the POST request.
formElement.querySelector("input[name='email']")?.setAttribute("name", "username");
formElement.submit();
});
return ( return (
<Template <Template
@ -33,29 +46,40 @@ export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.L
{realm.password && ( {realm.password && (
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post"> <form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}> <div className={cx(props.kcFormGroupClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}> {(() => {
{msg( const label = !realm.loginWithEmailAllowed
!realm.loginWithEmailAllowed ? "username"
? "username" : realm.registrationEmailAsUsername
: !realm.registrationEmailAsUsername ? "email"
? "usernameOrEmail" : "usernameOrEmail";
: "email",
)} const autoCompleteHelper: typeof label = label === "usernameOrEmail" ? "username" : label;
</label>
<input return (
tabIndex={1} <>
id="username" <label htmlFor={autoCompleteHelper} className={cx(props.kcLabelClass)}>
className={cx(props.kcInputClass)} {msg(label)}
name="username" </label>
defaultValue={login.username ?? ""} <input
type="text" tabIndex={1}
{...(usernameEditDisabled id={autoCompleteHelper}
? { "disabled": true } className={cx(props.kcInputClass)}
: { //NOTE: This is used by Google Chrome auto fill so we use it to tell
"autoFocus": true, //the browser how to pre fill the form but before submit we put it back
"autoComplete": "off", //to username because it is what keycloak expects.
})} name={autoCompleteHelper}
/> defaultValue={login.username ?? ""}
type="text"
{...(usernameEditDisabled
? { "disabled": true }
: {
"autoFocus": true,
"autoComplete": "off",
})}
/>
</>
);
})()}
</div> </div>
<div className={cx(props.kcFormGroupClass)}> <div className={cx(props.kcFormGroupClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}> <label htmlFor="password" className={cx(props.kcLabelClass)}>