diff --git a/native/account/log-in-panel.react.js b/native/account/log-in-panel.react.js
--- a/native/account/log-in-panel.react.js
+++ b/native/account/log-in-panel.react.js
@@ -180,7 +180,7 @@
   };
 
   onChangeUsernameInputText: (text: string) => void = text => {
-    this.props.logInState.setState({ usernameInputText: text });
+    this.props.logInState.setState({ usernameInputText: text.trim() });
   };
 
   onUsernameKeyPress: (event: KeyPressEvent) => void = event => {
diff --git a/web/account/log-in-form.react.js b/web/account/log-in-form.react.js
--- a/web/account/log-in-form.react.js
+++ b/web/account/log-in-form.react.js
@@ -51,6 +51,10 @@
     setUsername(e.target.value);
   }, []);
 
+  const onUsernameBlur = React.useCallback(() => {
+    setUsername(untrimmedUsername => untrimmedUsername.trim());
+  }, []);
+
   const onPasswordChange = React.useCallback(e => {
     invariant(e.target instanceof HTMLInputElement, 'target not input');
     setPassword(e.target.value);
@@ -133,6 +137,7 @@
               placeholder="Username"
               value={username}
               onChange={onUsernameChange}
+              onBlur={onUsernameBlur}
               ref={usernameInputRef}
               disabled={inputDisabled}
             />
diff --git a/web/modals/input.react.js b/web/modals/input.react.js
--- a/web/modals/input.react.js
+++ b/web/modals/input.react.js
@@ -9,6 +9,7 @@
   +placeholder: string,
   +value: string,
   +onChange: (value: SyntheticEvent<HTMLInputElement>) => mixed,
+  +onBlur?: (value: SyntheticEvent<HTMLInputElement>) => mixed,
   +disabled?: boolean,
   +label?: string,
   +id?: string,