2

Hi I create a login form using react-bootstrap, mdbootstrap and formik. I want a login spinner to be shown each time user presses login button. I've figured out how to do it however I have a trouble with placing the bootstrap spinner in the same line as the login button

I want to achieve something like this enter image description here

Here is my code

render() {
        return (
            <Formik
                validationSchema={schema}
                onSubmit={this.handleSubmit}
                initialValues={{username: '', password: ''}}>
                {
                    formProps => (
                        <Form name='form' onSubmit={formProps.handleSubmit}>
                            <Form.Group noValidate controlId="loginForm.username">
                                <Form.Label>Adres e-mail</Form.Label>
                                <Form.Control
                                    type="text"
                                    name="username"
                                    value={formProps.values.username}
                                    onChange={e => {
                                        formProps.handleChange(e);
                                        const {username} = formProps.initialValues;
                                        if (formProps.values.username === username) {
                                            formProps.setFieldTouched('username', false)
                                        }
                                    }}
                                    isInvalid={!!formProps.touched.username && !!formProps.errors.username}
                                />
                                <Form.Control.Feedback type="invalid">
                                    {formProps.errors.username}
                                </Form.Control.Feedback>
                            </Form.Group>
                            <Form.Group controlId="loginForm.password">
                                <Form.Label>Hasło</Form.Label>
                                <Form.Control
                                    type="password"
                                    name="password"
                                    value={formProps.values.password}
                                    onChange={e => {
                                        formProps.handleChange(e);
                                        const {password} = formProps.initialValues;
                                        if (formProps.values.password === password) {
                                            formProps.setFieldTouched('password', false)
                                        }
                                    }}
                                    isInvalid={!!formProps.touched.password && !!formProps.errors.password}
                                >
                                </Form.Control>
                                <Form.Control.Feedback type="invalid">
                                    {formProps.errors.password}
                                </Form.Control.Feedback>
                            </Form.Group>
                            <Form.Group controlId="loginForm.loginBtn">
                                <div className="d-inline-block">
                                <Button variant="primary" type="submit">
                                    Zaloguj się
                                </Button>
                                <Spinner animation="border" variant="info" />
                                </div>
                            </Form.Group>
                        </Form>
                    )
                }
            </Formik>
        )
    }

EDIT: coeden: codesandbox.io/s/quirky-blackburn-z7gtt

Clyde Barrow
  • 1,924
  • 8
  • 30
  • 60

3 Answers3

5

You can use <div class="d-flex align-items-center"> instead of <div className="d-inline-block"> as a wrapper for the button and spinner.

Clarity
  • 10,730
  • 2
  • 25
  • 35
  • @ClydeBarrow sorry, the class has to be `align-items-center`, I've updated the answer. – Clarity Sep 04 '19 at 07:11
  • but it only made the top of the button and the top of the spinner align in the line - not the center of the spinner and the ceneter of the button – Clyde Barrow Sep 04 '19 at 10:52
  • If you use `
    ` for the button and spinner wrapper, it will _vertically_ align your button and the spinner. I just tried it in your sandbox and it works.
    – Clarity Sep 04 '19 at 11:23
1

An easy way to achieve this is to add a custom class to the Spinner. Giving that class negative bottom margin will pull the spinner down so that it's in line with the button.

Updated React:

<Spinner animation="border" variant="primary" className="centered-spinner" />

CSS:

.centered-spinner {
    margin-bottom: -7px;
}

Centered spinner result image

Timo
  • 233
  • 1
  • 11
  • 1
    hardcoding margin values like this is a brittle approach. If some of the dimensions of any of the elements change (for ex. button height), this will break. – Clarity Sep 03 '19 at 09:46
  • Fair point. I agree your answer (using Flexbox on the container) is better in most cases. – Timo Sep 03 '19 at 10:07
0

Here is what you need to change in the code:

import React from "react";
import ReactDOM from "react-dom";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import Spinner from "react-bootstrap/Spinner";
import "./styles.css";
import "bootstrap-css-only/css/bootstrap.min.css";
import "mdbreact/dist/css/mdb.css";
function App() {
  const [isSubmitted, submitForm] = React.useState(false);

  return (
    <Form
      name="form"
      onSubmit={e => {
        e.preventDefault();
        submitForm(true);
      }}
    >
      <Form.Group noValidate controlId="loginForm.username">
        <Form.Label>Adres e-mail</Form.Label>
        <Form.Control
          type="text"
          name="username"
          value={"aaaa"}
          onChange={e => {}}
        />
      </Form.Group>
      <Form.Group controlId="loginForm.loginBtn">
        <div className="d-flex justify-content-start">
          <Button variant="primary" type="submit">
            {!isSubmitted && "Zaloguj się"}
            {isSubmitted && <Spinner animation="border" variant="info" />}
          </Button>
        </div>
      </Form.Group>
    </Form>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

I have used the React.useState hook to change the state in the function.

Here is the Live Example: https://codesandbox.io/s/upbeat-cerf-rb8x1

Harish Soni
  • 1,796
  • 12
  • 27