React Bootstrap Modal
A React Bootstrap modal component: open the dialog from state, close it on Escape or a backdrop click. Static, centered, scrollable and fullscreen variants.
Use a modal when you need the user's attention before they go on: to confirm a delete, fill in a short form or read an important message. The page behind it dims and stays out of reach until the modal closes.
Modal is a React component, so you open it with state instead of Bootstrap's data-bs-toggle attributes. It looks and animates like Bootstrap's modal, without Bootstrap's JavaScript or react-bootstrap. It is in the free and PRO versions of AdminKit for React.
Example
Keep a show state in the component that has the button. show opens the modal, and onHide is called when the user presses Escape or clicks next to the dialog. Inside Modal you write the header, body and footer as in Bootstrap.
import { useState } from "react";
import { CloseButton } from "@/components/bootstrap/close-button";
import { Modal } from "@/components/bootstrap/modal";
export function DeleteProject() {
const [show, setShow] = useState(false);
const close = () => setShow(false);
return (
<>
<button type="button" className="btn btn-danger" onClick={() => setShow(true)}>
Delete project
</button>
<Modal show={show} onHide={close} aria-labelledby="delete-title">
<div className="modal-header">
<h2 className="modal-title h5" id="delete-title">Delete project</h2>
<CloseButton onClick={close} />
</div>
<div className="modal-body">This cannot be undone.</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={close}>Cancel</button>
<button type="button" className="btn btn-danger" onClick={close}>Delete</button>
</div>
</Modal>
</>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
show | boolean | Whether the modal is open | |
onHide | () => void | Called on Escape and on a backdrop click; set show to false here | |
onExited | () => void | Called once the modal has faded out | |
backdrop | boolean | "static" | true | "static": a click outside shakes the dialog instead of closing it; false: no backdrop |
keyboard | boolean | true | Escape closes the modal |
dialogClassName | string | Classes for .modal-dialog: modal-lg, modal-dialog-centered, ... | |
contentClassName | string | Classes for .modal-content | |
contentAs | ElementType | "div" | "form" for a dialog that is a form |
contentProps | object | Other props for .modal-content, such as onSubmit |
Other props, such as className, id and aria-labelledby, go to the .modal element. The component is in src/components/bootstrap/modal.tsx, if you want to read or change it.
Static backdrop
Sometimes the user has to make a choice before the modal can close. With backdrop="static" and keyboard={false}, a click next to the dialog or Escape makes it bounce instead of closing.
<Modal
show={show}
onHide={close}
backdrop="static"
keyboard={false}
aria-labelledby="unsaved-title"
>
<div className="modal-header">
<h2 className="modal-title h5" id="unsaved-title">Unsaved changes</h2>
</div>
<div className="modal-body">Save your changes before you leave this page?</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={discard}>Discard</button>
<button type="button" className="btn btn-primary" onClick={save}>Save</button>
</div>
</Modal>Centered, scrollable and sizes
Bootstrap's .modal-dialog classes go in dialogClassName:
| Class | Effect |
|---|---|
modal-dialog-centered | Centers the dialog vertically |
modal-dialog-scrollable | Scrolls the body instead of the page when the content is long |
modal-sm, modal-lg, modal-xl | 400px, 900px and 1140px wide (600px by default) |
modal-fullscreen | Covers the whole window; modal-fullscreen-md-down only below a breakpoint |
<Modal
show={show}
onHide={close}
dialogClassName="modal-dialog-centered modal-lg"
aria-labelledby="invite-title"
>
<div className="modal-header">
<h2 className="modal-title h5" id="invite-title">Invite members</h2>
<CloseButton onClick={close} />
</div>
<div className="modal-body">A large, vertically centered dialog.</div>
</Modal>For a colored modal, as in the demo, give the modal className="modal-colored modal-primary" (or another theme color).
Form in a modal
To put a form in a modal, make the modal itself the form with contentAs="form". The submit button in the footer then submits it, and so does Enter in a field:
<Modal
show={show}
onHide={close}
contentAs="form"
contentProps={{
onSubmit: (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
rename(new FormData(event.currentTarget).get("name") as string);
close();
},
}}
aria-labelledby="rename-title"
>
<div className="modal-header">
<h2 className="modal-title h5" id="rename-title">Rename project</h2>
<CloseButton onClick={close} />
</div>
<div className="modal-body">
<label htmlFor="project-name" className="form-label">Name</label>
<input id="project-name" name="name" className="form-control" required />
</div>
<div className="modal-footer">
<button type="submit" className="btn btn-primary">Save</button>
</div>
</Modal>Accessibility
- The modal has
role="dialog"andaria-modal="true". Give it a title and pointaria-labelledbyat the title'sid. - When it opens, the focus moves into the modal, and Tab and Shift+Tab stay inside it. When it closes, the focus goes back to the element that had it, usually the button that opened it.
- Escape closes the modal, unless
keyboard={false}. Then keep a visible button that closes it. CloseButtonhasaria-label="Close".
Related
- Next.js Bootstrap modal: the same component in AdminKit for Next.js
- Bootstrap 5 modal: the modal of the HTML version
- Offcanvas: a panel that slides in from the side
- Modals demo: default, colored, centered and sized modals
Last updated on
List group
React Bootstrap list group markup in AdminKit: lists rendered from arrays, selectable items from state, NavLink items, badges and flush lists in cards.
Offcanvas
A React offcanvas component on Bootstrap's markup: a side panel opened from state, four placements, backdrop and scroll options, a responsive sidebar mode.