diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js
index 5316235fe0..a772e72c5a 100644
--- a/src/components/structures/auth/ForgotPassword.js
+++ b/src/components/structures/auth/ForgotPassword.js
@@ -124,13 +124,7 @@ module.exports = React.createClass({
         });
     },
 
-    async onServerDetailsNextPhaseClick(ev) {
-        ev.stopPropagation();
-        // TODO: TravisR - Capture the user's input somehow else
-        if (this._serverConfigRef) {
-            // Just to make sure the user's input gets captured
-            await this._serverConfigRef.validateServer();
-        }
+    async onServerDetailsNextPhaseClick() {
         this.setState({
             phase: PHASE_FORGOT,
         });
@@ -160,25 +154,19 @@ module.exports = React.createClass({
 
     renderServerDetails() {
         const ServerConfig = sdk.getComponent("auth.ServerConfig");
-        const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
 
         if (SdkConfig.get()['disable_custom_urls']) {
             return null;
         }
 
-        // TODO: TravisR - Pull out server discovery from ServerConfig to disable the next button?
-        return <div>
-            <ServerConfig
-                ref={r => this._serverConfigRef = r}
-                serverConfig={this.props.serverConfig}
-                onServerConfigChange={this.props.onServerConfigChange}
-                delayTimeMs={0} />
-            <AccessibleButton className="mx_Login_submit"
-                onClick={this.onServerDetailsNextPhaseClick}
-            >
-                {_t("Next")}
-            </AccessibleButton>
-        </div>;
+        return <ServerConfig
+            serverConfig={this.props.serverConfig}
+            onServerConfigChange={this.props.onServerConfigChange}
+            delayTimeMs={0}
+            onAfterSubmit={this.onServerDetailsNextPhaseClick}
+            submitText={_t("Next")}
+            submitClass="mx_Login_submit"
+        />;
     },
 
     renderForgot() {
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index af9370f2db..68b440d064 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -20,11 +20,11 @@ limitations under the License.
 
 import React from 'react';
 import PropTypes from 'prop-types';
-import { _t, _td } from '../../../languageHandler';
+import {_t, _td} from '../../../languageHandler';
 import sdk from '../../../index';
 import Login from '../../../Login';
 import SdkConfig from '../../../SdkConfig';
-import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
+import {messageForResourceLimitError} from '../../../utils/ErrorUtils';
 import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
 
 // For validating phone numbers without country codes
@@ -283,13 +283,7 @@ module.exports = React.createClass({
         this.props.onRegisterClick();
     },
 
-    async onServerDetailsNextPhaseClick(ev) {
-        ev.stopPropagation();
-        // TODO: TravisR - Capture the user's input somehow else
-        if (this._serverConfigRef) {
-            // Just to make sure the user's input gets captured
-            await this._serverConfigRef.validateServer();
-        }
+    async onServerDetailsNextPhaseClick() {
         this.setState({
             phase: PHASE_LOGIN,
         });
@@ -421,7 +415,6 @@ module.exports = React.createClass({
 
     renderServerComponent() {
         const ServerConfig = sdk.getComponent("auth.ServerConfig");
-        const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
 
         if (SdkConfig.get()['disable_custom_urls']) {
             return null;
@@ -431,26 +424,19 @@ module.exports = React.createClass({
             return null;
         }
 
-        const serverDetails = <ServerConfig
-            ref={r => this._serverConfigRef = r}
+        const serverDetailsProps = {};
+        if (PHASES_ENABLED) {
+            serverDetailsProps.onAfterSubmit = this.onServerDetailsNextPhaseClick;
+            serverDetailsProps.submitText = _t("Next");
+            serverDetailsProps.submitClass = "mx_Login_submit";
+        }
+
+        return <ServerConfig
             serverConfig={this.props.serverConfig}
             onServerConfigChange={this.props.onServerConfigChange}
             delayTimeMs={250}
+            {...serverDetailsProps}
         />;
-
-        let nextButton = null;
-        if (PHASES_ENABLED) {
-            // TODO: TravisR - Pull out server discovery from ServerConfig to disable the next button?
-            nextButton = <AccessibleButton className="mx_Login_submit"
-                onClick={this.onServerDetailsNextPhaseClick}>
-                {_t("Next")}
-            </AccessibleButton>;
-        }
-
-        return <div>
-            {serverDetails}
-            {nextButton}
-        </div>;
     },
 
     renderLoginComponentForStep() {
diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js
index faab8190bd..f516816033 100644
--- a/src/components/structures/auth/Registration.js
+++ b/src/components/structures/auth/Registration.js
@@ -286,13 +286,7 @@ module.exports = React.createClass({
         });
     },
 
-    async onServerDetailsNextPhaseClick(ev) {
-        ev.stopPropagation();
-        // TODO: TravisR - Capture the user's input somehow else
-        if (this._serverConfigRef) {
-            // Just to make sure the user's input gets captured
-            await this._serverConfigRef.validateServer();
-        }
+    async onServerDetailsNextPhaseClick() {
         this.setState({
             phase: PHASE_REGISTRATION,
         });
@@ -337,7 +331,6 @@ module.exports = React.createClass({
         const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector");
         const ServerConfig = sdk.getComponent("auth.ServerConfig");
         const ModularServerConfig = sdk.getComponent("auth.ModularServerConfig");
-        const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
 
         if (SdkConfig.get()['disable_custom_urls']) {
             return null;
@@ -354,45 +347,41 @@ module.exports = React.createClass({
             </div>;
         }
 
+        const serverDetailsProps = {};
+        if (PHASES_ENABLED) {
+            serverDetailsProps.onAfterSubmit = this.onServerDetailsNextPhaseClick;
+            serverDetailsProps.submitText = _t("Next");
+            serverDetailsProps.submitClass = "mx_Login_submit";
+        }
+
         let serverDetails = null;
         switch (this.state.serverType) {
             case ServerType.FREE:
                 break;
             case ServerType.PREMIUM:
                 serverDetails = <ModularServerConfig
-                    ref={r => this._serverConfigRef = r}
                     serverConfig={this.props.serverConfig}
                     onServerConfigChange={this.props.onServerConfigChange}
                     delayTimeMs={250}
+                    {...serverDetailsProps}
                 />;
                 break;
             case ServerType.ADVANCED:
                 serverDetails = <ServerConfig
-                    ref={r => this._serverConfigRef = r}
                     serverConfig={this.props.serverConfig}
                     onServerConfigChange={this.props.onServerConfigChange}
                     delayTimeMs={250}
+                    {...serverDetailsProps}
                 />;
                 break;
         }
 
-        let nextButton = null;
-        if (PHASES_ENABLED) {
-            // TODO: TravisR - Pull out server discovery from ServerConfig to disable the next button?
-            nextButton = <AccessibleButton className="mx_Login_submit"
-                onClick={this.onServerDetailsNextPhaseClick}
-            >
-                {_t("Next")}
-            </AccessibleButton>;
-        }
-
         return <div>
             <ServerTypeSelector
                 selected={this.state.serverType}
                 onChange={this.onServerTypeChange}
             />
             {serverDetails}
-            {nextButton}
         </div>;
     },
 
diff --git a/src/components/views/auth/ModularServerConfig.js b/src/components/views/auth/ModularServerConfig.js
index ea22577dbd..5a3bc23596 100644
--- a/src/components/views/auth/ModularServerConfig.js
+++ b/src/components/views/auth/ModularServerConfig.js
@@ -41,6 +41,16 @@ export default class ModularServerConfig extends React.PureComponent {
         serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
 
         delayTimeMs: PropTypes.number, // time to wait before invoking onChanged
+
+        // Called after the component calls onServerConfigChange
+        onAfterSubmit: PropTypes.func,
+
+        // Optional text for the submit button. If falsey, no button will be shown.
+        submitText: PropTypes.string,
+
+        // Optional class for the submit button. Only applies if the submit button
+        // is to be rendered.
+        submitClass: PropTypes.string,
     };
 
     static defaultProps = {
@@ -119,6 +129,16 @@ export default class ModularServerConfig extends React.PureComponent {
         this.setState({ hsUrl });
     };
 
+    onSubmit = async (ev) => {
+        ev.preventDefault();
+        ev.stopPropagation();
+        await this.validateServer();
+
+        if (this.props.onAfterSubmit) {
+            this.props.onAfterSubmit();
+        }
+    };
+
     _waitThenInvoke(existingTimeoutId, fn) {
         if (existingTimeoutId) {
             clearTimeout(existingTimeoutId);
@@ -128,6 +148,16 @@ export default class ModularServerConfig extends React.PureComponent {
 
     render() {
         const Field = sdk.getComponent('elements.Field');
+        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
+
+        const submitButton = this.props.submitText
+            ? <AccessibleButton
+                element="button"
+                type="submit"
+                className={this.props.submitClass}
+                onClick={this.onSubmit}
+                disabled={this.state.busy}>{this.props.submitText}</AccessibleButton>
+            : null;
 
         return (
             <div className="mx_ServerConfig">
@@ -141,15 +171,18 @@ export default class ModularServerConfig extends React.PureComponent {
                         </a>,
                     },
                 )}
-                <div className="mx_ServerConfig_fields">
-                    <Field id="mx_ServerConfig_hsUrl"
-                        label={_t("Server Name")}
-                        placeholder={this.props.serverConfig.hsUrl}
-                        value={this.state.hsUrl}
-                        onBlur={this.onHomeserverBlur}
-                        onChange={this.onHomeserverChange}
-                    />
-                </div>
+                <form onSubmit={this.onSubmit} autoComplete={false} action={null}>
+                    <div className="mx_ServerConfig_fields">
+                        <Field id="mx_ServerConfig_hsUrl"
+                            label={_t("Server Name")}
+                            placeholder={this.props.serverConfig.hsUrl}
+                            value={this.state.hsUrl}
+                            onBlur={this.onHomeserverBlur}
+                            onChange={this.onHomeserverChange}
+                        />
+                    </div>
+                    {submitButton}
+                </form>
             </div>
         );
     }
diff --git a/src/components/views/auth/ServerConfig.js b/src/components/views/auth/ServerConfig.js
index 096e461efe..3967f49f18 100644
--- a/src/components/views/auth/ServerConfig.js
+++ b/src/components/views/auth/ServerConfig.js
@@ -30,12 +30,22 @@ import SdkConfig from "../../../SdkConfig";
 
 export default class ServerConfig extends React.PureComponent {
     static propTypes = {
-        onServerConfigChange: PropTypes.func,
+        onServerConfigChange: PropTypes.func.isRequired,
 
         // The current configuration that the user is expecting to change.
         serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
 
         delayTimeMs: PropTypes.number, // time to wait before invoking onChanged
+
+        // Called after the component calls onServerConfigChange
+        onAfterSubmit: PropTypes.func,
+
+        // Optional text for the submit button. If falsey, no button will be shown.
+        submitText: PropTypes.string,
+
+        // Optional class for the submit button. Only applies if the submit button
+        // is to be rendered.
+        submitClass: PropTypes.string,
     };
 
     static defaultProps = {
@@ -124,6 +134,16 @@ export default class ServerConfig extends React.PureComponent {
         this.setState({ isUrl });
     };
 
+    onSubmit = async (ev) => {
+        ev.preventDefault();
+        ev.stopPropagation();
+        await this.validateServer();
+
+        if (this.props.onAfterSubmit) {
+            this.props.onAfterSubmit();
+        }
+    };
+
     _waitThenInvoke(existingTimeoutId, fn) {
         if (existingTimeoutId) {
             clearTimeout(existingTimeoutId);
@@ -138,11 +158,21 @@ export default class ServerConfig extends React.PureComponent {
 
     render() {
         const Field = sdk.getComponent('elements.Field');
+        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
 
         const errorText = this.state.errorText
             ? <span className='mx_ServerConfig_error'>{this.state.errorText}</span>
             : null;
 
+        const submitButton = this.props.submitText
+            ? <AccessibleButton
+                  element="button"
+                  type="submit"
+                  className={this.props.submitClass}
+                  onClick={this.onSubmit}
+                  disabled={this.state.busy}>{this.props.submitText}</AccessibleButton>
+            : null;
+
         return (
             <div className="mx_ServerConfig">
                 <h3>{_t("Other servers")}</h3>
@@ -152,24 +182,27 @@ export default class ServerConfig extends React.PureComponent {
                     </a>,
                 })}
                 {errorText}
-                <div className="mx_ServerConfig_fields">
-                    <Field id="mx_ServerConfig_hsUrl"
-                        label={_t("Homeserver URL")}
-                        placeholder={this.props.serverConfig.hsUrl}
-                        value={this.state.hsUrl}
-                        onBlur={this.onHomeserverBlur}
-                        onChange={this.onHomeserverChange}
-                        disabled={this.state.busy}
-                    />
-                    <Field id="mx_ServerConfig_isUrl"
-                        label={_t("Identity Server URL")}
-                        placeholder={this.props.serverConfig.isUrl}
-                        value={this.state.isUrl}
-                        onBlur={this.onIdentityServerBlur}
-                        onChange={this.onIdentityServerChange}
-                        disabled={this.state.busy}
-                    />
-                </div>
+                <form onSubmit={this.onSubmit} autoComplete={false} action={null}>
+                    <div className="mx_ServerConfig_fields">
+                        <Field id="mx_ServerConfig_hsUrl"
+                            label={_t("Homeserver URL")}
+                            placeholder={this.props.serverConfig.hsUrl}
+                            value={this.state.hsUrl}
+                            onBlur={this.onHomeserverBlur}
+                            onChange={this.onHomeserverChange}
+                            disabled={this.state.busy}
+                        />
+                        <Field id="mx_ServerConfig_isUrl"
+                            label={_t("Identity Server URL")}
+                            placeholder={this.props.serverConfig.isUrl}
+                            value={this.state.isUrl}
+                            onBlur={this.onIdentityServerBlur}
+                            onChange={this.onIdentityServerChange}
+                            disabled={this.state.busy}
+                        />
+                    </div>
+                    {submitButton}
+                </form>
             </div>
         );
     }