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,20 +46,28 @@ 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
? "usernameOrEmail" ? "email"
: "email", : "usernameOrEmail";
)}
const autoCompleteHelper: typeof label = label === "usernameOrEmail" ? "username" : label;
return (
<>
<label htmlFor={autoCompleteHelper} className={cx(props.kcLabelClass)}>
{msg(label)}
</label> </label>
<input <input
tabIndex={1} tabIndex={1}
id="username" id={autoCompleteHelper}
className={cx(props.kcInputClass)} className={cx(props.kcInputClass)}
name="username" //NOTE: This is used by Google Chrome auto fill so we use it to tell
//the browser how to pre fill the form but before submit we put it back
//to username because it is what keycloak expects.
name={autoCompleteHelper}
defaultValue={login.username ?? ""} defaultValue={login.username ?? ""}
type="text" type="text"
{...(usernameEditDisabled {...(usernameEditDisabled
@ -56,6 +77,9 @@ export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.L
"autoComplete": "off", "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)}>