@react-ui-org/react-ui 0.52.1 → 0.54.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (261) hide show
  1. package/README.md +10 -7
  2. package/dist/react-ui.css +5 -3
  3. package/dist/react-ui.development.css +11302 -0
  4. package/dist/react-ui.development.js +1588 -0
  5. package/dist/react-ui.js +1 -1
  6. package/package.json +66 -77
  7. package/src/{lib/components → components}/Alert/Alert.jsx +1 -1
  8. package/src/{lib/components/Alert/README.mdx → components/Alert/README.md} +84 -100
  9. package/src/{lib/components → components}/Badge/Badge.jsx +1 -1
  10. package/src/{lib/components → components}/Badge/Badge.scss +1 -1
  11. package/src/components/Badge/README.md +103 -0
  12. package/src/{lib/components → components}/Button/Button.jsx +1 -1
  13. package/src/components/Button/README.md +580 -0
  14. package/src/{lib/components → components}/ButtonGroup/ButtonGroup.jsx +11 -9
  15. package/src/{lib/components/ButtonGroup/README.mdx → components/ButtonGroup/README.md} +128 -134
  16. package/src/{lib/components → components}/Card/Card.jsx +1 -1
  17. package/src/components/Card/README.md +314 -0
  18. package/src/{lib/components/CheckboxField/README.mdx → components/CheckboxField/README.md} +96 -108
  19. package/src/{lib/components/FileInputField/README.mdx → components/FileInputField/README.md} +83 -95
  20. package/src/{lib/components → components}/FormLayout/FormLayout.jsx +4 -4
  21. package/src/components/FormLayout/README.md +462 -0
  22. package/src/{lib/components → components}/Grid/Grid.jsx +2 -2
  23. package/src/components/Grid/README.md +281 -0
  24. package/src/{lib/components → components}/InputGroup/InputGroup.jsx +28 -19
  25. package/src/{lib/components → components}/InputGroup/InputGroup.scss +4 -5
  26. package/src/{lib/components/InputGroup/README.mdx → components/InputGroup/README.md} +162 -165
  27. package/src/{lib/components → components}/Modal/Modal.jsx +6 -6
  28. package/src/components/Modal/README.md +1090 -0
  29. package/src/components/Modal/_hooks/useModalScrollPrevention.js +37 -0
  30. package/src/{lib/components/Paper/README.mdx → components/Paper/README.md} +18 -30
  31. package/src/{lib/components/Popover/README.mdx → components/Popover/README.md} +102 -132
  32. package/src/{lib/components/Radio/README.mdx → components/Radio/README.md} +122 -134
  33. package/src/{lib/components → components}/Radio/Radio.jsx +11 -12
  34. package/src/{lib/components → components}/Radio/Radio.scss +0 -5
  35. package/src/components/ScrollView/README.md +503 -0
  36. package/src/{lib/components → components}/ScrollView/ScrollView.jsx +12 -3
  37. package/src/components/SelectField/README.md +681 -0
  38. package/src/components/Table/README.md +259 -0
  39. package/src/{lib/components → components}/Table/Table.jsx +4 -1
  40. package/src/{lib/components → components}/Table/_components/TableHeaderCell/TableHeaderCell.jsx +1 -1
  41. package/src/{lib/components/Tabs/README.mdx → components/Tabs/README.md} +117 -134
  42. package/src/{lib/components → components}/Tabs/TabsItem.jsx +3 -3
  43. package/src/components/Text/README.md +220 -0
  44. package/src/components/TextArea/README.md +359 -0
  45. package/src/{lib/components/TextField/README.mdx → components/TextField/README.md} +336 -342
  46. package/src/{lib/components/TextLink/README.mdx → components/TextLink/README.md} +19 -31
  47. package/src/{lib/components/Toggle/README.mdx → components/Toggle/README.md} +98 -110
  48. package/src/components/Toolbar/README.md +359 -0
  49. package/src/{lib/components → components}/Toolbar/_helpers/getAlignClassName.js +12 -4
  50. package/src/components/_helpers/getRootPriorityClassName.js +15 -0
  51. package/src/{lib/index.js → index.js} +6 -0
  52. package/src/{lib/provider → provider}/RUIProvider.jsx +17 -11
  53. package/src/{lib/styles → styles}/tools/_caret.scss +1 -1
  54. package/src/{lib/styles → styles}/tools/form-fields/_box-field-elements.scss +1 -1
  55. package/src/{lib/styles → styles}/tools/form-fields/_inline-field-elements.scss +2 -2
  56. package/src/{lib/theme.scss → theme.scss} +4 -3
  57. package/CONTRIBUTING.md +0 -137
  58. package/dist/lib.development.js +0 -3179
  59. package/dist/lib.js +0 -1
  60. package/public/racom.svg +0 -11
  61. package/src/lib/components/Badge/README.mdx +0 -126
  62. package/src/lib/components/Button/README.mdx +0 -581
  63. package/src/lib/components/Card/README.mdx +0 -326
  64. package/src/lib/components/FormLayout/README.mdx +0 -501
  65. package/src/lib/components/Grid/README.mdx +0 -299
  66. package/src/lib/components/Modal/README.mdx +0 -1360
  67. package/src/lib/components/Modal/_hooks/useModalScrollPrevention.js +0 -35
  68. package/src/lib/components/ScrollView/README.mdx +0 -521
  69. package/src/lib/components/SelectField/README.mdx +0 -693
  70. package/src/lib/components/Table/README.mdx +0 -275
  71. package/src/lib/components/Text/README.mdx +0 -241
  72. package/src/lib/components/TextArea/README.mdx +0 -366
  73. package/src/lib/components/Toolbar/README.mdx +0 -386
  74. package/src/{lib/components → components}/Alert/Alert.scss +0 -0
  75. package/src/{lib/components → components}/Alert/_settings.scss +0 -0
  76. package/src/{lib/components → components}/Alert/_theme.scss +0 -0
  77. package/src/{lib/components → components}/Alert/_tools.scss +0 -0
  78. package/src/{lib/components → components}/Alert/index.js +0 -0
  79. package/src/{lib/components → components}/Badge/index.js +0 -0
  80. package/src/{lib/components → components}/Button/Button.scss +0 -0
  81. package/src/{lib/components → components}/Button/_base.scss +0 -0
  82. package/src/{lib/components → components}/Button/_priorities.scss +0 -0
  83. package/src/{lib/components → components}/Button/_settings.scss +0 -0
  84. package/src/{lib/components → components}/Button/_theme.scss +0 -0
  85. package/src/{lib/components → components}/Button/_tools.scss +0 -0
  86. package/src/{lib/components → components}/Button/helpers/getRootLabelVisibilityClassName.js +0 -0
  87. package/src/{lib/components/_helpers → components/Button/helpers}/getRootPriorityClassName.js +0 -0
  88. package/src/{lib/components → components}/Button/index.js +0 -0
  89. package/src/{lib/components → components}/ButtonGroup/ButtonGroup.scss +0 -0
  90. package/src/{lib/components → components}/ButtonGroup/ButtonGroupContext.js +0 -0
  91. package/src/{lib/components → components}/ButtonGroup/_theme.scss +0 -0
  92. package/src/{lib/components → components}/ButtonGroup/index.js +0 -0
  93. package/src/{lib/components → components}/Card/Card.scss +0 -0
  94. package/src/{lib/components → components}/Card/CardBody.jsx +0 -0
  95. package/src/{lib/components → components}/Card/CardFooter.jsx +0 -0
  96. package/src/{lib/components → components}/Card/_theme.scss +0 -0
  97. package/src/{lib/components → components}/Card/_tools.scss +0 -0
  98. package/src/{lib/components → components}/Card/index.js +0 -0
  99. package/src/{lib/components → components}/CheckboxField/CheckboxField.jsx +0 -0
  100. package/src/{lib/components → components}/CheckboxField/CheckboxField.scss +0 -0
  101. package/src/{lib/components → components}/CheckboxField/index.js +0 -0
  102. package/src/{lib/components → components}/FileInputField/FileInputField.jsx +0 -0
  103. package/src/{lib/components → components}/FileInputField/FileInputField.scss +0 -0
  104. package/src/{lib/components → components}/FileInputField/index.js +0 -0
  105. package/src/{lib/components → components}/FormLayout/FormLayout.scss +0 -0
  106. package/src/{lib/components → components}/FormLayout/FormLayoutContext.js +0 -0
  107. package/src/{lib/components → components}/FormLayout/FormLayoutCustomField.jsx +4 -4
  108. package/src/{lib/components → components}/FormLayout/FormLayoutCustomField.scss +0 -0
  109. package/src/{lib/components → components}/FormLayout/_theme.scss +0 -0
  110. package/src/{lib/components → components}/FormLayout/index.js +0 -0
  111. package/src/{lib/components → components}/Grid/Grid.scss +0 -0
  112. package/src/{lib/components → components}/Grid/GridSpan.jsx +0 -0
  113. package/src/{lib/components → components}/Grid/_helpers/generateResponsiveCustomProperties.js +0 -0
  114. package/src/{lib/components → components}/Grid/_settings.scss +0 -0
  115. package/src/{lib/components → components}/Grid/_tools.scss +0 -0
  116. package/src/{lib/components → components}/Grid/index.js +0 -0
  117. package/src/{lib/components → components}/InputGroup/InputGroupContext.js +0 -0
  118. package/src/{lib/components → components}/InputGroup/_theme.scss +0 -0
  119. package/src/{lib/components → components}/InputGroup/index.js +0 -0
  120. package/src/{lib/components → components}/Modal/Modal.scss +0 -0
  121. package/src/{lib/components → components}/Modal/ModalBody.jsx +0 -0
  122. package/src/{lib/components → components}/Modal/ModalBody.scss +0 -0
  123. package/src/{lib/components → components}/Modal/ModalCloseButton.jsx +1 -1
  124. package/src/{lib/components → components}/Modal/ModalCloseButton.scss +0 -0
  125. package/src/{lib/components → components}/Modal/ModalContent.jsx +0 -0
  126. package/src/{lib/components → components}/Modal/ModalContent.scss +0 -0
  127. package/src/{lib/components → components}/Modal/ModalFooter.jsx +0 -0
  128. package/src/{lib/components → components}/Modal/ModalFooter.scss +0 -0
  129. package/src/{lib/components → components}/Modal/ModalHeader.jsx +0 -0
  130. package/src/{lib/components → components}/Modal/ModalHeader.scss +0 -0
  131. package/src/{lib/components → components}/Modal/ModalTitle.jsx +0 -0
  132. package/src/{lib/components → components}/Modal/ModalTitle.scss +0 -0
  133. package/src/{lib/components → components}/Modal/_helpers/getJustifyClassName.js +0 -0
  134. package/src/{lib/components → components}/Modal/_helpers/getPositionClassName.js +0 -0
  135. package/src/{lib/components → components}/Modal/_helpers/getScrollingClassName.js +0 -0
  136. package/src/{lib/components → components}/Modal/_helpers/getSizeClassName.js +0 -0
  137. package/src/{lib/components → components}/Modal/_hooks/useModalFocus.js +0 -0
  138. package/src/{lib/components → components}/Modal/_settings.scss +0 -0
  139. package/src/{lib/components → components}/Modal/_theme.scss +0 -0
  140. package/src/{lib/components → components}/Modal/index.js +0 -0
  141. package/src/{lib/components → components}/Paper/Paper.jsx +0 -0
  142. package/src/{lib/components → components}/Paper/Paper.scss +0 -0
  143. package/src/{lib/components → components}/Paper/_theme.scss +0 -0
  144. package/src/{lib/components → components}/Paper/index.js +0 -0
  145. package/src/{lib/components → components}/Popover/Popover.jsx +0 -0
  146. package/src/{lib/components → components}/Popover/Popover.scss +0 -0
  147. package/src/{lib/components → components}/Popover/PopoverWrapper.jsx +0 -0
  148. package/src/{lib/components → components}/Popover/PopoverWrapper.scss +0 -0
  149. package/src/{lib/components → components}/Popover/_helpers/getRootAlignmentClassName.js +0 -0
  150. package/src/{lib/components → components}/Popover/_helpers/getRootSideClassName.js +0 -0
  151. package/src/{lib/components → components}/Popover/_theme.scss +0 -0
  152. package/src/{lib/components → components}/Popover/index.js +0 -0
  153. package/src/{lib/components → components}/Radio/index.js +0 -0
  154. package/src/{lib/components → components}/ScrollView/ScrollView.scss +0 -0
  155. package/src/{lib/components → components}/ScrollView/_helpers/getElementsPositionDifference.js +0 -0
  156. package/src/{lib/components → components}/ScrollView/_hooks/useLoadResizeHook.js +0 -0
  157. package/src/{lib/components → components}/ScrollView/_hooks/useScrollPositionHook.js +0 -0
  158. package/src/{lib/components → components}/ScrollView/index.js +0 -0
  159. package/src/{lib/components → components}/SelectField/SelectField.jsx +0 -0
  160. package/src/{lib/components → components}/SelectField/SelectField.scss +0 -0
  161. package/src/{lib/components → components}/SelectField/_components/Option/Option.jsx +0 -0
  162. package/src/{lib/components → components}/SelectField/_components/Option/index.js +0 -0
  163. package/src/{lib/components → components}/SelectField/index.js +0 -0
  164. package/src/{lib/components → components}/Table/Table.scss +0 -0
  165. package/src/{lib/components → components}/Table/_components/TableBodyCell/TableBodyCell.jsx +0 -0
  166. package/src/{lib/components → components}/Table/_components/TableBodyCell/index.js +0 -0
  167. package/src/{lib/components → components}/Table/_components/TableCell.scss +0 -0
  168. package/src/{lib/components → components}/Table/_components/TableHeaderCell/index.js +0 -0
  169. package/src/{lib/components → components}/Table/_settings.scss +0 -0
  170. package/src/{lib/components → components}/Table/index.js +0 -0
  171. package/src/{lib/components → components}/Tabs/Tabs.jsx +0 -0
  172. package/src/{lib/components → components}/Tabs/Tabs.scss +0 -0
  173. package/src/{lib/components → components}/Tabs/TabsItem.scss +0 -0
  174. package/src/{lib/components → components}/Tabs/_theme.scss +0 -0
  175. package/src/{lib/components → components}/Tabs/index.js +0 -0
  176. package/src/{lib/components → components}/Text/Text.jsx +0 -0
  177. package/src/{lib/components → components}/Text/Text.scss +0 -0
  178. package/src/{lib/components → components}/Text/_helpers/getRootClampClassName.js +0 -0
  179. package/src/{lib/components → components}/Text/_helpers/getRootHyphensClassName.js +0 -0
  180. package/src/{lib/components → components}/Text/_helpers/getRootWordWrappingClassName.js +0 -0
  181. package/src/{lib/components → components}/Text/index.js +0 -0
  182. package/src/{lib/components → components}/TextArea/TextArea.jsx +0 -0
  183. package/src/{lib/components → components}/TextArea/TextArea.scss +0 -0
  184. package/src/{lib/components → components}/TextArea/index.js +0 -0
  185. package/src/{lib/components → components}/TextField/TextField.jsx +0 -0
  186. package/src/{lib/components → components}/TextField/TextField.scss +0 -0
  187. package/src/{lib/components → components}/TextField/index.js +0 -0
  188. package/src/{lib/components → components}/TextLink/TextLink.jsx +1 -1
  189. /package/src/{lib/components → components}/TextLink/TextLink.scss +0 -0
  190. /package/src/{lib/components → components}/TextLink/_theme.scss +0 -0
  191. /package/src/{lib/components → components}/TextLink/index.js +0 -0
  192. /package/src/{lib/components → components}/Toggle/Toggle.jsx +0 -0
  193. /package/src/{lib/components → components}/Toggle/Toggle.scss +0 -0
  194. /package/src/{lib/components → components}/Toggle/index.js +0 -0
  195. /package/src/{lib/components → components}/Toolbar/Toolbar.jsx +0 -0
  196. /package/src/{lib/components → components}/Toolbar/Toolbar.scss +0 -0
  197. /package/src/{lib/components → components}/Toolbar/ToolbarGroup.jsx +0 -0
  198. /package/src/{lib/components → components}/Toolbar/ToolbarItem.jsx +0 -0
  199. /package/src/{lib/components → components}/Toolbar/_helpers/getJustifyClassName.js +0 -0
  200. /package/src/{lib/components → components}/Toolbar/_theme.scss +0 -0
  201. /package/src/{lib/components → components}/Toolbar/index.js +0 -0
  202. /package/src/{lib/components → components}/_helpers/getRootColorClassName.js +0 -0
  203. /package/src/{lib/components → components}/_helpers/getRootSizeClassName.js +0 -0
  204. /package/src/{lib/components → components}/_helpers/getRootValidationStateClassName.js +0 -0
  205. /package/src/{lib/components → components}/_helpers/isChildrenEmpty.js +0 -0
  206. /package/src/{lib/components → components}/_helpers/resolveContextOrProp.js +0 -0
  207. /package/src/{lib/components → components}/_helpers/transferProps.js +0 -0
  208. /package/src/{lib/foundation.scss → foundation.scss} +0 -0
  209. /package/src/{lib/helpers.scss → helpers.scss} +0 -0
  210. /package/src/{lib/provider → provider}/RUIContext.jsx +0 -0
  211. /package/src/{lib/provider → provider}/index.js +0 -0
  212. /package/src/{lib/provider → provider}/withGlobalProps.jsx +0 -0
  213. /package/src/{lib/styles → styles}/_utilities.scss +0 -0
  214. /package/src/{lib/styles → styles}/elements/_code.scss +0 -0
  215. /package/src/{lib/styles → styles}/elements/_links.scss +0 -0
  216. /package/src/{lib/styles → styles}/elements/_lists.scss +0 -0
  217. /package/src/{lib/styles → styles}/elements/_page.scss +0 -0
  218. /package/src/{lib/styles → styles}/elements/_rulers.scss +0 -0
  219. /package/src/{lib/styles → styles}/elements/_small.scss +0 -0
  220. /package/src/{lib/styles → styles}/generic/_box-sizing.scss +0 -0
  221. /package/src/{lib/styles → styles}/generic/_focus.scss +0 -0
  222. /package/src/{lib/styles → styles}/generic/_forms.scss +0 -0
  223. /package/src/{lib/styles → styles}/generic/_reset.scss +0 -0
  224. /package/src/{lib/styles → styles}/generic/_shared.scss +0 -0
  225. /package/src/{lib/styles → styles}/helpers/_animation.scss +0 -0
  226. /package/src/{lib/styles → styles}/settings/_animations.scss +0 -0
  227. /package/src/{lib/styles → styles}/settings/_breakpoints.scss +0 -0
  228. /package/src/{lib/styles → styles}/settings/_escaped-characters.scss +0 -0
  229. /package/src/{lib/styles → styles}/settings/_form-fields.scss +0 -0
  230. /package/src/{lib/styles → styles}/settings/_forms.scss +0 -0
  231. /package/src/{lib/styles → styles}/settings/_utilities.scss +0 -0
  232. /package/src/{lib/styles → styles}/settings/_z-indexes.scss +0 -0
  233. /package/src/{lib/styles → styles}/theme/_accessibility.scss +0 -0
  234. /package/src/{lib/styles → styles}/theme/_borders.scss +0 -0
  235. /package/src/{lib/styles → styles}/theme/_code.scss +0 -0
  236. /package/src/{lib/styles → styles}/theme/_form-fields.scss +0 -0
  237. /package/src/{lib/styles → styles}/theme/_links.scss +0 -0
  238. /package/src/{lib/styles → styles}/theme/_lists.scss +0 -0
  239. /package/src/{lib/styles → styles}/theme/_page.scss +0 -0
  240. /package/src/{lib/styles → styles}/theme/_spacing.scss +0 -0
  241. /package/src/{lib/styles → styles}/theme/_typography.scss +0 -0
  242. /package/src/{lib/styles → styles}/theme-constants/_breakpoints.scss +0 -0
  243. /package/src/{lib/styles → styles}/theme-constants/_colors.scss +0 -0
  244. /package/src/{lib/styles → styles}/theme-constants/_svg.scss +0 -0
  245. /package/src/{lib/styles → styles}/tools/_accessibility.scss +0 -0
  246. /package/src/{lib/styles → styles}/tools/_breakpoint.scss +0 -0
  247. /package/src/{lib/styles → styles}/tools/_colors.scss +0 -0
  248. /package/src/{lib/styles → styles}/tools/_reset.scss +0 -0
  249. /package/src/{lib/styles → styles}/tools/_scrollbar.scss +0 -0
  250. /package/src/{lib/styles → styles}/tools/_spacing.scss +0 -0
  251. /package/src/{lib/styles → styles}/tools/_string.scss +0 -0
  252. /package/src/{lib/styles → styles}/tools/_svg.scss +0 -0
  253. /package/src/{lib/styles → styles}/tools/_transition.scss +0 -0
  254. /package/src/{lib/styles → styles}/tools/_utilities.scss +0 -0
  255. /package/src/{lib/styles → styles}/tools/form-fields/_box-field-layout.scss +0 -0
  256. /package/src/{lib/styles → styles}/tools/form-fields/_box-field-sizes.scss +0 -0
  257. /package/src/{lib/styles → styles}/tools/form-fields/_foundation.scss +0 -0
  258. /package/src/{lib/styles → styles}/tools/form-fields/_inline-field-layout.scss +0 -0
  259. /package/src/{lib/styles → styles}/tools/form-fields/_variants.scss +0 -0
  260. /package/src/{lib/translations → translations}/en.js +0 -0
  261. /package/src/{lib/utils → utils}/classNames.js +0 -0
@@ -1,1360 +0,0 @@
1
- ---
2
- name: Modal
3
- menu: 'Miscellaneous'
4
- route: /components/modal
5
- ---
6
-
7
- # Modal
8
-
9
- Modal allows prompting users to take or complete an action.
10
-
11
- import {
12
- Playground,
13
- Props,
14
- } from 'docz'
15
- import {
16
- Button,
17
- CheckboxField,
18
- FormLayout,
19
- Modal,
20
- ModalBody,
21
- ModalCloseButton,
22
- ModalContent,
23
- ModalFooter,
24
- ModalHeader,
25
- ModalTitle,
26
- Radio,
27
- ScrollView,
28
- TextArea,
29
- TextField,
30
- Toolbar,
31
- ToolbarGroup,
32
- ToolbarItem,
33
- } from '../..'
34
- import Icon from '../../../docs/_components/Icon'
35
-
36
- ## Basic Usage
37
-
38
- To implement the Modal component, you need to import it first:
39
-
40
- ```js
41
- import {
42
- Modal,
43
- ModalHeader,
44
- ModalBody,
45
- ModalCloseButton,
46
- ModalContent,
47
- ModalFooter,
48
- ModalTitle,
49
- } from '@react-ui-org/react-ui';
50
- ```
51
-
52
- And use it:
53
-
54
- <Playground>
55
- {() => {
56
- const [modalOpen, setModalOpen] = React.useState(false);
57
- const modalPrimaryButtonRef = React.useRef();
58
- const modalCloseButtonRef = React.useRef();
59
- return (
60
- <>
61
- <Button label="Launch modal" onClick={() => setModalOpen(true)} />
62
- <div>
63
- {modalOpen && (
64
- <Modal
65
- closeButtonRef={modalCloseButtonRef}
66
- primaryButtonRef={modalPrimaryButtonRef}
67
- >
68
- <ModalHeader>
69
- <ModalTitle>Delete the user?</ModalTitle>
70
- <ModalCloseButton onClick={() => setModalOpen(false)} />
71
- </ModalHeader>
72
- <ModalBody>
73
- <ModalContent>
74
- <p>
75
- Do you really want to delete the user <code>admin</code>?
76
- This cannot be undone.
77
- </p>
78
- </ModalContent>
79
- </ModalBody>
80
- <ModalFooter>
81
- <Button
82
- color="danger"
83
- label="Delete"
84
- onClick={() => setModalOpen(false)}
85
- ref={modalPrimaryButtonRef}
86
- />
87
- <Button
88
- color="secondary"
89
- label="Close"
90
- onClick={() => setModalOpen(false)}
91
- priority="outline"
92
- ref={modalCloseButtonRef}
93
- />
94
- </ModalFooter>
95
- </Modal>
96
- )}
97
- </div>
98
- </>
99
- );
100
- }}
101
- </Playground>
102
-
103
- See [API](#api) for all available options.
104
-
105
- ## General Guidelines
106
-
107
- - Use modals to **confirm an action,** display a **blocking alert**, or reveal
108
- **contextual options or settings** that cannot be displayed in line with the
109
- parent content.
110
-
111
- - **The title** should communicate the **purpose of the modal** rather than a
112
- generic text. Eg. “Delete the user?” tells more than “Are you sure?” or
113
- “Warning”.
114
-
115
- - **Modal actions** should correspond to the modal purpose, too. E.g. “Delete”
116
- tells better what happens rather than “OK”.
117
-
118
- - Modal **automatically focuses the first non-disabled form field** by default
119
- which allows users to confirm the modal by hitting the enter key. When no
120
- field is found then the primary button (in the footer) is focused. If there
121
- are neither, it tries to focus any other focusable elements. In case there
122
- are none, or [autoFocus](#autoFocus) is disabled, Modal itself is focused.
123
-
124
- - **Avoid stacking** of modals. While it may technically work, the modal is just
125
- not designed for that.
126
-
127
- 📖 [Read more about modals at Nielsen Norman Group.][nng-modal]
128
-
129
- ## Composition
130
-
131
- Modal is decomposed into the following components:
132
-
133
- - [Modal](#api)
134
- - [ModalHeader](#modalheader-1)
135
- - [ModalTitle](#modaltitle)
136
- - [ModalCloseButton](#modalclosebutton)
137
- - [ModalBody](#modalbody-1)
138
- - [ModalContent](#modalcontent)
139
- (may be wrapped with [ScrollView](/components/scroll-view))
140
- - [ModalFooter](#modalfooter-1)
141
-
142
- Using different combinations, you can compose different kinds of modals,
143
- e.g. dialog modal, blocking modal, scrollable modal, etc.
144
-
145
- <Playground>
146
- {() => {
147
- const [modalOpen, setModalOpen] = React.useState(null);
148
- const modalPrimaryButtonRef = React.useRef();
149
- const modalCloseButtonRef = React.useRef();
150
- return (
151
- <>
152
- <Button
153
- label="Launch blocking modal without title"
154
- onClick={() => {
155
- setModalOpen(1);
156
- setTimeout(() => setModalOpen(null), 2500);
157
- }}
158
- />
159
- <Button
160
- label="Launch blocking modal with title"
161
- onClick={() => {
162
- setModalOpen(2);
163
- setTimeout(() => setModalOpen(null), 3500);
164
- }}
165
- />
166
- <Button
167
- label="Launch modal as dialog"
168
- onClick={() => setModalOpen(3)}
169
- />
170
- <Button
171
- label="Launch modal as form"
172
- onClick={() => setModalOpen(4)}
173
- />
174
- <div>
175
- {modalOpen === 1 && (
176
- <Modal>
177
- <ModalBody>
178
- <ModalContent>
179
- <p className="text-center">
180
- Application is being loaded.
181
- <span className="d-inline-flex align-items-center animation-spin-counterclockwise">
182
- <Icon icon="loading" />
183
- </span>
184
- </p>
185
- </ModalContent>
186
- </ModalBody>
187
- </Modal>
188
- )}
189
- {modalOpen === 2 && (
190
- <Modal>
191
- <ModalHeader>
192
- <ModalTitle>Action finished</ModalTitle>
193
- </ModalHeader>
194
- <ModalBody>
195
- <ModalContent>
196
- <p>
197
- Action has been successfully finished.
198
- You will be redirected within a few seconds.
199
- </p>
200
- </ModalContent>
201
- </ModalBody>
202
- </Modal>
203
- )}
204
- {modalOpen === 3 && (
205
- <Modal
206
- closeButtonRef={modalCloseButtonRef}
207
- primaryButtonRef={modalPrimaryButtonRef}
208
- >
209
- <ModalHeader>
210
- <ModalTitle>Delete the user?</ModalTitle>
211
- <ModalCloseButton onClick={() => setModalOpen(false)} />
212
- </ModalHeader>
213
- <ModalBody>
214
- <ModalContent>
215
- <p>
216
- Do you really want to delete the user <code>admin</code>?
217
- This cannot be undone.
218
- </p>
219
- </ModalContent>
220
- </ModalBody>
221
- <ModalFooter>
222
- <Button
223
- color="danger"
224
- label="Delete"
225
- onClick={() => setModalOpen(false)}
226
- ref={modalPrimaryButtonRef}
227
- />
228
- <Button
229
- color="secondary"
230
- label="Close"
231
- onClick={() => setModalOpen(false)}
232
- priority="outline"
233
- ref={modalCloseButtonRef}
234
- />
235
- </ModalFooter>
236
- </Modal>
237
- )}
238
- {modalOpen === 4 && (
239
- <Modal
240
- closeButtonRef={modalCloseButtonRef}
241
- primaryButtonRef={modalPrimaryButtonRef}
242
- >
243
- <ModalHeader>
244
- <ModalTitle>Add new user</ModalTitle>
245
- <ModalCloseButton onClick={() => setModalOpen(false)} />
246
- </ModalHeader>
247
- <ModalBody>
248
- <ModalContent>
249
- <FormLayout fieldLayout="horizontal">
250
- <TextField label="Username" />
251
- <TextField label="Password" type="password" />
252
- </FormLayout>
253
- </ModalContent>
254
- </ModalBody>
255
- <ModalFooter>
256
- <Button
257
- label="Save"
258
- onClick={() => setModalOpen(false)}
259
- ref={modalPrimaryButtonRef}
260
- />
261
- <Button
262
- color="secondary"
263
- label="Close"
264
- onClick={() => setModalOpen(false)}
265
- priority="outline"
266
- ref={modalCloseButtonRef}
267
- />
268
- </ModalFooter>
269
- </Modal>
270
- )}
271
- </div>
272
- </>
273
- );
274
- }}
275
- </Playground>
276
-
277
- ### ModalHeader
278
-
279
- ModalHeader is an optional part of the Modal which allows you to display the title
280
- of the modal and its close button.
281
-
282
- It is recommended to compose ModalHeader from the following elements. For title,
283
- use ModalTitle. For the close button, use ModalCloseButton, however it can
284
- be omitted if a close button is part of ModalFooter.
285
-
286
- There are two ways how to position elements within the ModalHeader:
287
-
288
- 1. You can use provided positioning. Place previously mentioned elements into
289
- the ModalHeader and use `justify` prop to set up the positioning of those
290
- elements.
291
- 2. You can customize positioning using another component (e.g.
292
- [Toolbar](/components/toolbar)). In that case, set `justify` to `stretch` and
293
- position elements on your own.
294
-
295
- <Playground>
296
- {() => {
297
- const [modalOpen, setModalOpen] = React.useState(false);
298
- const [variant, setVariant] = React.useState(null);
299
- const modalPrimaryButtonRef = React.useRef();
300
- const modalCloseButtonRef = React.useRef();
301
- return (
302
- <>
303
- <Button
304
- label="Launch with close button"
305
- onClick={() => {
306
- setModalOpen(true);
307
- setVariant(1);
308
- }}
309
- />
310
- <Button
311
- label="Launch without close button"
312
- onClick={() => {
313
- setModalOpen(true);
314
- setVariant(2);
315
- }}
316
- />
317
- <Button
318
- label="Launch without close button and with centered title"
319
- onClick={() => {
320
- setModalOpen(true);
321
- setVariant(3);
322
- }}
323
- />
324
- <Button
325
- label="Launch with custom layout"
326
- onClick={() => {
327
- setModalOpen(true);
328
- setVariant(4);
329
- }}
330
- />
331
- <div>
332
- {modalOpen && (
333
- <Modal
334
- closeButtonRef={modalCloseButtonRef}
335
- primaryButtonRef={modalPrimaryButtonRef}
336
- >
337
- {variant === 1 && (
338
- <ModalHeader>
339
- <ModalTitle>Delete the user?</ModalTitle>
340
- <ModalCloseButton onClick={() => setModalOpen(false)} />
341
- </ModalHeader>
342
- )}
343
- {variant === 2 && (
344
- <ModalHeader>
345
- <ModalTitle>Delete the user?</ModalTitle>
346
- </ModalHeader>
347
- )}
348
- {variant === 3 && (
349
- <ModalHeader justify="center">
350
- <ModalTitle>Delete the user?</ModalTitle>
351
- </ModalHeader>
352
- )}
353
- {variant === 4 && (
354
- <ModalHeader justify="stretch">
355
- <Toolbar justify="space-between">
356
- <ToolbarItem>
357
- {''}
358
- </ToolbarItem>
359
- <ToolbarItem>
360
- <ModalTitle>Delete the user?</ModalTitle>
361
- </ToolbarItem>
362
- <ToolbarItem>
363
- <ModalCloseButton onClick={() => setModalOpen(false)} />
364
- </ToolbarItem>
365
- </Toolbar>
366
- </ModalHeader>
367
- )}
368
- <ModalBody>
369
- <ModalContent>
370
- <p>
371
- Do you really want to delete the user <code>admin</code>?
372
- This cannot be undone.
373
- </p>
374
- </ModalContent>
375
- </ModalBody>
376
- <ModalFooter>
377
- <Button
378
- color="danger"
379
- label="Delete"
380
- onClick={() => setModalOpen(false)}
381
- ref={modalPrimaryButtonRef}
382
- />
383
- <Button
384
- color="secondary"
385
- label="Close"
386
- onClick={() => setModalOpen(false)}
387
- priority="outline"
388
- ref={modalCloseButtonRef}
389
- />
390
- </ModalFooter>
391
- </Modal>
392
- )}
393
- </div>
394
- </>
395
- );
396
- }}
397
- </Playground>
398
-
399
- ### ModalBody
400
-
401
- ModalBody is a mandatory part of the Modal which allows you to display the
402
- content of the Modal.
403
-
404
- Although the ModalBody allows you to display arbitrary content, you should not
405
- place content directly into the ModalBody, but wrap it with ModalContent first.
406
-
407
- In case your content is expected to be long, consider wrapping ModalContent
408
- with ScrollView. Check [Scrolling Long Content](#scrolling-long-content) section
409
- below.
410
-
411
- ### ModalFooter
412
-
413
- ModalFooter is an optional part of the Modal which allows you to display
414
- user actions.
415
-
416
- There are two ways to position buttons within the ModalFooter:
417
-
418
- 1. You can use provided positioning. Place Button component (or any arbitrary
419
- element) and use `justify` prop to set up the positioning of those elements.
420
- 2. You can customize positioning using another component (e.g.
421
- [Toolbar](/components/toolbar)). In that case, set `justify` to `stretch`
422
- and position elements on your own.
423
-
424
- <Playground>
425
- {() => {
426
- const [modalOpen, setModalOpen] = React.useState(false);
427
- const [modalJustify, setModalJustify] = React.useState('center');
428
- const modalPrimaryButtonRef = React.useRef();
429
- const modalCloseButtonRef = React.useRef();
430
- return (
431
- <>
432
- <Button
433
- label="Launch modal with footer variants"
434
- onClick={() => setModalOpen(true)}
435
- />
436
- <div>
437
- {modalOpen && (
438
- <Modal
439
- closeButtonRef={modalCloseButtonRef}
440
- primaryButtonRef={modalPrimaryButtonRef}
441
- >
442
- <ModalHeader>
443
- <ModalTitle>Footer justification</ModalTitle>
444
- <ModalCloseButton onClick={() => setModalOpen(false)} />
445
- </ModalHeader>
446
- <ModalBody>
447
- <ModalContent>
448
- <Radio
449
- label="Footer justification"
450
- onChange={(e) => setModalJustify(e.target.value)}
451
- options={[
452
- {
453
- label: 'start',
454
- value: 'start',
455
- },
456
- {
457
- label: 'center',
458
- value: 'center',
459
- },
460
- {
461
- label: 'end',
462
- value: 'end',
463
- },
464
- {
465
- label: 'space-between',
466
- value: 'space-between',
467
- },
468
- {
469
- label: 'stretch (with a custom layout)',
470
- value: 'stretch',
471
- },
472
- ]}
473
- value={modalJustify}
474
- />
475
- </ModalContent>
476
- </ModalBody>
477
- <ModalFooter justify={modalJustify}>
478
- {
479
- modalJustify === 'stretch'
480
- ? (
481
- <Toolbar justify="space-between">
482
- <ToolbarGroup>
483
- <ToolbarItem>
484
- <Button
485
- color="danger"
486
- label="Delete"
487
- onClick={() => setModalOpen(false)}
488
- ref={modalPrimaryButtonRef}
489
- />
490
- </ToolbarItem>
491
- <ToolbarItem>
492
- <Button
493
- color="warning"
494
- label="Archive"
495
- onClick={() => setModalOpen(false)}
496
- ref={modalPrimaryButtonRef}
497
- />
498
- </ToolbarItem>
499
- </ToolbarGroup>
500
- <ToolbarItem>
501
- <Button
502
- color="secondary"
503
- label="Close"
504
- onClick={() => setModalOpen(false)}
505
- priority="outline"
506
- ref={modalCloseButtonRef}
507
- />
508
- </ToolbarItem>
509
- </Toolbar>
510
- ) : (
511
- <>
512
- <Button
513
- label="OK"
514
- onClick={() => setModalOpen(false)}
515
- ref={modalPrimaryButtonRef}
516
- />
517
- <Button
518
- color="secondary"
519
- label="Close"
520
- onClick={() => setModalOpen(false)}
521
- priority="outline"
522
- ref={modalCloseButtonRef}
523
- />
524
- </>
525
- )
526
- }
527
- </ModalFooter>
528
- </Modal>
529
- )}
530
- </div>
531
- </>
532
- );
533
- }}
534
- </Playground>
535
-
536
- ## Sizes
537
-
538
- Modal is available in three fixed-width sizes: small, medium, large and fullscreen.
539
- Modals of any size automatically shrink when they cannot fit the screen width.
540
-
541
- <Playground>
542
- {() => {
543
- const [modalOpen, setModalOpen] = React.useState(false);
544
- const [modalSize, setModalSize] = React.useState('small');
545
- const modalPrimaryButtonRef = React.useRef();
546
- const modalCloseButtonRef = React.useRef();
547
- return (
548
- <>
549
- <Button
550
- label="Launch small modal"
551
- onClick={() => {
552
- setModalSize('small');
553
- setModalOpen(true);
554
- }}
555
- />
556
- <Button
557
- label="Launch medium modal"
558
- onClick={() => {
559
- setModalSize('medium');
560
- setModalOpen(true);
561
- }}
562
- />
563
- <Button
564
- label="Launch large modal"
565
- onClick={() => {
566
- setModalSize('large');
567
- setModalOpen(true);
568
- }}
569
- />
570
- <Button
571
- label="Launch fullscreen modal"
572
- onClick={() => {
573
- setModalSize('fullscreen');
574
- setModalOpen(true);
575
- }}
576
- />
577
- <div>
578
- {modalOpen && (
579
- <Modal
580
- closeButtonRef={modalCloseButtonRef}
581
- primaryButtonRef={modalPrimaryButtonRef}
582
- size={modalSize}
583
- >
584
- <ModalHeader>
585
- <ModalTitle>Delete the user?</ModalTitle>
586
- <ModalCloseButton onClick={() => setModalOpen(false)} />
587
- </ModalHeader>
588
- <ModalBody>
589
- <ModalContent>
590
- <p>
591
- Do you really want to delete the user <code>admin</code>?
592
- This cannot be undone.
593
- </p>
594
- </ModalContent>
595
- </ModalBody>
596
- <ModalFooter>
597
- <Button
598
- color="danger"
599
- label="Delete"
600
- onClick={() => setModalOpen(false)}
601
- ref={modalPrimaryButtonRef}
602
- />
603
- <Button
604
- color="secondary"
605
- label="Close"
606
- onClick={() => setModalOpen(false)}
607
- priority="outline"
608
- ref={modalCloseButtonRef}
609
- />
610
- </ModalFooter>
611
- </Modal>
612
- )}
613
- </div>
614
- </>
615
- );
616
- }}
617
- </Playground>
618
-
619
- On top of that, the modal can adjust to the width of its content.
620
-
621
- <Playground>
622
- {() => {
623
- const [modalOpen, setModalOpen] = React.useState(false);
624
- const modalPrimaryButtonRef = React.useRef();
625
- const modalCloseButtonRef = React.useRef();
626
- return (
627
- <>
628
- <Button
629
- label="Launch auto-width modal"
630
- onClick={() => setModalOpen(true)}
631
- />
632
- <div>
633
- {modalOpen && (
634
- <Modal
635
- closeButtonRef={modalCloseButtonRef}
636
- primaryButtonRef={modalPrimaryButtonRef}
637
- size="auto"
638
- >
639
- <ModalHeader>
640
- <ModalTitle>Delete the user?</ModalTitle>
641
- <ModalCloseButton onClick={() => setModalOpen(false)} />
642
- </ModalHeader>
643
- <ModalBody>
644
- <ModalContent>
645
- <p>
646
- Do you really want to delete the user <code>admin</code>?
647
- This cannot be undone.
648
- </p>
649
- </ModalContent>
650
- </ModalBody>
651
- <ModalFooter>
652
- <Button
653
- color="danger"
654
- label="Delete"
655
- onClick={() => setModalOpen(false)}
656
- ref={modalPrimaryButtonRef}
657
- />
658
- <Button
659
- color="secondary"
660
- label="Close"
661
- onClick={() => setModalOpen(false)}
662
- priority="outline"
663
- ref={modalCloseButtonRef}
664
- />
665
- </ModalFooter>
666
- </Modal>
667
- )}
668
- </div>
669
- </>
670
- );
671
- }}
672
- </Playground>
673
-
674
- ## Position
675
-
676
- Modal can be aligned either to the top or center of the screen.
677
-
678
- <Playground>
679
- {() => {
680
- const [modalOpen, setModalOpen] = React.useState(false);
681
- const [modalPosition, setModalPosition] = React.useState('center');
682
- const modalPrimaryButtonRef = React.useRef();
683
- const modalCloseButtonRef = React.useRef();
684
- return (
685
- <>
686
- <Button
687
- label="Launch modal at center"
688
- onClick={() => {
689
- setModalPosition('center');
690
- setModalOpen(true);
691
- }}
692
- />
693
- <Button
694
- label="Launch modal at top"
695
- onClick={() => {
696
- setModalPosition('top');
697
- setModalOpen(true);
698
- }}
699
- />
700
- <div>
701
- {modalOpen && (
702
- <Modal
703
- closeButtonRef={modalCloseButtonRef}
704
- position={modalPosition}
705
- primaryButtonRef={modalPrimaryButtonRef}
706
- >
707
- <ModalHeader>
708
- <ModalTitle>Delete the user?</ModalTitle>
709
- <ModalCloseButton onClick={() => setModalOpen(false)} />
710
- </ModalHeader>
711
- <ModalBody>
712
- <ModalContent>
713
- <p>
714
- Do you really want to delete the user <code>admin</code>?
715
- This cannot be undone.
716
- </p>
717
- </ModalContent>
718
- </ModalBody>
719
- <ModalFooter>
720
- <Button
721
- color="danger"
722
- label="Delete"
723
- onClick={() => setModalOpen(false)}
724
- ref={modalPrimaryButtonRef}
725
- />
726
- <Button
727
- color="secondary"
728
- label="Close"
729
- onClick={() => setModalOpen(false)}
730
- priority="outline"
731
- ref={modalCloseButtonRef}
732
- />
733
- </ModalFooter>
734
- </Modal>
735
- )}
736
- </div>
737
- </>
738
- );
739
- }}
740
- </Playground>
741
-
742
- ## Forms in Modals
743
-
744
- You can safely place a FormLayout into a Modal of any size, including the
745
- auto-width Modal.
746
-
747
- <Playground>
748
- {() => {
749
- const [modalOpen, setModalOpen] = React.useState(false);
750
- const [agree, setAgree] = React.useState(true);
751
- const modalPrimaryButtonRef = React.useRef();
752
- const modalCloseButtonRef = React.useRef();
753
- return (
754
- <>
755
- <Button
756
- label="Launch auto-width modal with auto-width form"
757
- onClick={() => setModalOpen(true)}
758
- />
759
- <div>
760
- {modalOpen && (
761
- <Modal
762
- closeButtonRef={modalCloseButtonRef}
763
- primaryButtonRef={modalPrimaryButtonRef}
764
- size="auto"
765
- >
766
- <ModalHeader>
767
- <ModalTitle>Auto-width form inside auto-width modal</ModalTitle>
768
- <ModalCloseButton onClick={() => setModalOpen(false)} />
769
- </ModalHeader>
770
- <ModalBody>
771
- <ModalContent>
772
- <FormLayout autoWidth fieldLayout="horizontal">
773
- <TextField
774
- label="A form element"
775
- validationState="warning"
776
- validationText={`Account with this name already exists,
777
- pick a different one.`
778
- }
779
- />
780
- <TextField label="Another form element" />
781
- <TextField label="Yet another one" />
782
- <CheckboxField
783
- checked={agree}
784
- label="I agree"
785
- onChange={() => setAgree(!agree)}
786
- />
787
- </FormLayout>
788
- </ModalContent>
789
- </ModalBody>
790
- <ModalFooter>
791
- <Button
792
- color="primary"
793
- label="Save"
794
- onClick={() => setModalOpen(false)}
795
- ref={modalPrimaryButtonRef}
796
- />
797
- <Button
798
- color="secondary"
799
- label="Cancel"
800
- onClick={() => setModalOpen(false)}
801
- priority="outline"
802
- ref={modalCloseButtonRef}
803
- />
804
- </ModalFooter>
805
- </Modal>
806
- )}
807
- </div>
808
- </>
809
- );
810
- }}
811
- </Playground>
812
-
813
- 👉 Inside Modal, we recommend using the `autoWidth` option of FormLayout. This
814
- prevents the Modal from unwanted horizontal expansion when a long validation
815
- text pops up during user's interaction with the form.
816
-
817
- 👉 Beware of horizontal FormLayout inside `small` modals. While automatic
818
- overflow handling comes to the rescue in this kind of scenario, you will be
819
- better off with the combination of auto-sized modal and horizontal FormLayout.
820
-
821
- ## Keyboard Control
822
-
823
- Modal can be controlled either by mouse or keyboard. To enhance user
824
- experience, primary action can be fired by pressing `Enter` key and the modal
825
- can be closed by pressing the `Escape` key.
826
-
827
- To enable it, you just need to pass a reference to the buttons using
828
- `primaryButtonRef` and `closeButtonRef` props on Modal. The advantage of passing
829
- the reference to the button is that if the button is disabled, the key press
830
- will not fire the event.
831
-
832
- ## Autofocus
833
-
834
- Autofocus is implemented to enhance the user experience by automatically
835
- focusing an element within the Modal.
836
-
837
- How does it work? It tries to find `input`, `textarea`, and `select` elements
838
- inside of Modal and moves focus onto the first non-disabled one. If none is
839
- found and the `primaryButtonRef` prop on Modal is set, then the primary button
840
- is focused. If there are neither, it tries to focus any other focusable elements.
841
- In case there are none or `autoFocus` is disabled, Modal itself is focused.
842
-
843
- <Playground>
844
- {() => {
845
- const [modalOpen, setModalOpen] = React.useState(null);
846
- const modalPrimaryButtonRef = React.useRef();
847
- const modalCloseButtonRef = React.useRef();
848
- return (
849
- <>
850
- <Button
851
- label="Launch modal with autofocus and form"
852
- onClick={() => setModalOpen(1)}
853
- />
854
- <Button
855
- label="Launch modal with autofocus"
856
- onClick={() => setModalOpen(2)}
857
- />
858
- <Button
859
- label="Launch modal with autofocus disabled"
860
- onClick={() => setModalOpen(3)}
861
- />
862
- <div>
863
- {modalOpen === 1 && (
864
- <Modal
865
- closeButtonRef={modalCloseButtonRef}
866
- primaryButtonRef={modalPrimaryButtonRef}
867
- >
868
- <ModalHeader>
869
- <ModalTitle>Modal with autoFocus and form</ModalTitle>
870
- <ModalCloseButton onClick={() => setModalOpen(null)} />
871
- </ModalHeader>
872
- <ModalBody>
873
- <ModalContent>
874
- <FormLayout autoWidth fieldLayout="horizontal">
875
- <TextField
876
- disabled
877
- label="A form element"
878
- />
879
- <TextField label="Another form element" />
880
- <TextArea label="Yet another one" />
881
- </FormLayout>
882
- </ModalContent>
883
- </ModalBody>
884
- <ModalFooter>
885
- <Button
886
- label="Submit"
887
- onClick={() => setModalOpen(null)}
888
- ref={modalPrimaryButtonRef}
889
- />
890
- <Button
891
- color="secondary"
892
- label="Close"
893
- onClick={() => setModalOpen(null)}
894
- priority="outline"
895
- ref={modalCloseButtonRef}
896
- />
897
- </ModalFooter>
898
- </Modal>
899
- )}
900
- {modalOpen === 2 && (
901
- <Modal
902
- closeButtonRef={modalCloseButtonRef}
903
- primaryButtonRef={modalPrimaryButtonRef}
904
- >
905
- <ModalHeader>
906
- <ModalTitle>Modal with autoFocus enabled with no form</ModalTitle>
907
- <ModalCloseButton onClick={() => setModalOpen(null)} />
908
- </ModalHeader>
909
- <ModalBody>
910
- <ModalContent>
911
- <p>
912
- This Modal autofocuses the primary button or any other
913
- focusable element.
914
- </p>
915
- </ModalContent>
916
- </ModalBody>
917
- <ModalFooter>
918
- <Button
919
- label="Acknowledge"
920
- onClick={() => setModalOpen(null)}
921
- ref={modalPrimaryButtonRef}
922
- />
923
- <Button
924
- color="secondary"
925
- label="Close"
926
- onClick={() => setModalOpen(null)}
927
- priority="outline"
928
- ref={modalCloseButtonRef}
929
- />
930
- </ModalFooter>
931
- </Modal>
932
- )}
933
- {modalOpen === 3 && (
934
- <Modal
935
- autoFocus={false}
936
- closeButtonRef={modalCloseButtonRef}
937
- primaryButtonRef={modalPrimaryButtonRef}
938
- >
939
- <ModalHeader>
940
- <ModalTitle>Modal with autoFocus disabled</ModalTitle>
941
- </ModalHeader>
942
- <ModalBody>
943
- <ModalContent>
944
- <p>
945
- This Modal focuses the Modal element itself.
946
- </p>
947
- </ModalContent>
948
- </ModalBody>
949
- <ModalFooter>
950
- <Button
951
- label="Acknowledge"
952
- onClick={() => setModalOpen(null)}
953
- ref={modalPrimaryButtonRef}
954
- />
955
- <Button
956
- color="secondary"
957
- label="Close"
958
- onClick={() => setModalOpen(null)}
959
- priority="outline"
960
- ref={modalCloseButtonRef}
961
- />
962
- </ModalFooter>
963
- </Modal>
964
- )}
965
- </div>
966
- </>
967
- );
968
- }}
969
- </Playground>
970
-
971
- ## Scrolling Long Content
972
-
973
- When modals become too long for the user's viewport or device, they scroll
974
- independent of the page itself. This can be done in three ways using the
975
- `scrolling` option of the ModalBody component:
976
-
977
- - `auto` (default) — ModalBody is responsible for scrolling,
978
- - `custom` — you must provide a custom component to handle scrolling,
979
- typically an instance of [ScrollView](/components/scroll-view) wrapping
980
- ModalContent,
981
- - `none` — entire Modal is responsible for scrolling.
982
-
983
- <Playground>
984
- {() => {
985
- const [modalOpen, setModalOpen] = React.useState(false);
986
- const [modalScrolling, setModalScrolling] = React.useState('auto');
987
- const modalCloseButtonRef = React.useRef();
988
- const modalPrimaryButtonRef = React.useRef();
989
- const modalContent = (
990
- <ModalContent>
991
- <p>
992
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
993
- commodo ligula eget dolor. Aenean massa.
994
- </p>
995
- <p>
996
- Cum sociis natoque penatibus et magnis dis parturient montes,
997
- nascetur ridiculus mus. Donec quam felis, ultricies nec,
998
- pellentesque eu, pretium quis, sem.
999
- </p>
1000
- <p>
1001
- Nulla consequat massa quis enim. Donec pede justo, fringilla
1002
- vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
1003
- ut, imperdiet a, venenatis vitae, justo.
1004
- </p>
1005
- <p>
1006
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
1007
- commodo ligula eget dolor. Aenean massa.
1008
- </p>
1009
- <p>
1010
- Cum sociis natoque penatibus et magnis dis parturient montes,
1011
- nascetur ridiculus mus. Donec quam felis, ultricies nec,
1012
- pellentesque eu, pretium quis, sem.
1013
- </p>
1014
- <p>
1015
- Nulla consequat massa quis enim. Donec pede justo, fringilla
1016
- vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
1017
- ut, imperdiet a, venenatis vitae, justo.
1018
- </p>
1019
- <p>
1020
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
1021
- commodo ligula eget dolor. Aenean massa.
1022
- </p>
1023
- <p>
1024
- Cum sociis natoque penatibus et magnis dis parturient montes,
1025
- nascetur ridiculus mus. Donec quam felis, ultricies nec,
1026
- pellentesque eu, pretium quis, sem.
1027
- </p>
1028
- <p>
1029
- Nulla consequat massa quis enim. Donec pede justo, fringilla
1030
- vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
1031
- ut, imperdiet a, venenatis vitae, justo.
1032
- </p>
1033
- <p>
1034
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
1035
- commodo ligula eget dolor. Aenean massa.
1036
- </p>
1037
- <p>
1038
- Cum sociis natoque penatibus et magnis dis parturient montes,
1039
- nascetur ridiculus mus. Donec quam felis, ultricies nec,
1040
- pellentesque eu, pretium quis, sem.
1041
- </p>
1042
- <p>
1043
- Nulla consequat massa quis enim. Donec pede justo, fringilla
1044
- vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
1045
- ut, imperdiet a, venenatis vitae, justo.
1046
- </p>
1047
- <p>
1048
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
1049
- commodo ligula eget dolor. Aenean massa.
1050
- </p>
1051
- <p>
1052
- Cum sociis natoque penatibus et magnis dis parturient montes,
1053
- nascetur ridiculus mus. Donec quam felis, ultricies nec,
1054
- pellentesque eu, pretium quis, sem.
1055
- </p>
1056
- <p>
1057
- Nulla consequat massa quis enim. Donec pede justo, fringilla
1058
- vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
1059
- ut, imperdiet a, venenatis vitae, justo.
1060
- </p>
1061
- </ModalContent>
1062
- )
1063
- return (
1064
- <>
1065
- <Button
1066
- label="Launch modal with scrolling body"
1067
- onClick={() => {
1068
- setModalScrolling('auto');
1069
- setModalOpen(true);
1070
- }}
1071
- />
1072
- <Button
1073
- label="Launch modal with ScrollView"
1074
- onClick={() => {
1075
- setModalScrolling('custom');
1076
- setModalOpen(true);
1077
- }}
1078
- />
1079
- <Button
1080
- label="Launch modal with non-scrolling body"
1081
- onClick={() => {
1082
- setModalScrolling('none');
1083
- setModalOpen(true);
1084
- }}
1085
- />
1086
- <div>
1087
- {modalOpen && (
1088
- <Modal
1089
- autoFocus={modalScrolling !== 'none'}
1090
- closeButtonRef={modalCloseButtonRef}
1091
- primaryButtonRef={modalPrimaryButtonRef}
1092
- size="small"
1093
- >
1094
- <ModalHeader>
1095
- <ModalTitle>Modal with long content</ModalTitle>
1096
- <ModalCloseButton onClick={() => setModalOpen(false)} />
1097
- </ModalHeader>
1098
- <ModalBody scrolling={modalScrolling}>
1099
- {
1100
- modalScrolling === 'custom'
1101
- ? (
1102
- <ScrollView>
1103
- {modalContent}
1104
- </ScrollView>
1105
- )
1106
- : modalContent
1107
- }
1108
- </ModalBody>
1109
- <ModalFooter>
1110
- <Button
1111
- label="OK"
1112
- onClick={() => setModalOpen(false)}
1113
- ref={modalPrimaryButtonRef}
1114
- />
1115
- <Button
1116
- color="secondary"
1117
- label="Close"
1118
- onClick={() => setModalOpen(false)}
1119
- priority="outline"
1120
- ref={modalCloseButtonRef}
1121
- />
1122
- </ModalFooter>
1123
- </Modal>
1124
- )}
1125
- </div>
1126
- </>
1127
- );
1128
- }}
1129
- </Playground>
1130
-
1131
- ### Long Content and Autofocus
1132
-
1133
- 👉 If you have a Modal with `scrolling` set to `none`, you may want to disable
1134
- `autoFocus` to prevent the modal from scrolling to the end immediately after
1135
- being opened.
1136
-
1137
- ## Prevent Scrolling Underneath the Modal
1138
-
1139
- You can choose the mode in which Modal prevents the scroll of the page underneath.
1140
- Default mode prevents scrolling on `<body>` element and accounts for the scrollbar
1141
- width. If you choose `off`, there will be no scroll prevention. If you need more
1142
- flexibility, define your methods `start` (called on Modal's mount) and `reset`
1143
- (called on Modal unmount) wrapped by an object and handle scroll prevention
1144
- yourself.
1145
-
1146
- <Playground>
1147
- {() => {
1148
- const [modalOpen, setModalOpen] = React.useState(null);
1149
- const modalPrimaryButtonRef = React.useRef();
1150
- const modalCloseButtonRef = React.useRef();
1151
- const customScrollPreventionObject = {
1152
- start: () => {
1153
- // YOUR CUSTOM SCROLL PREVENTING LOGIC GOES HERE
1154
- window.document.body.style.overflowY = 'hidden'
1155
- },
1156
- reset: () => {
1157
- // YOUR CUSTOM SCROLL RE-ENABLING LOGIC GOES HERE
1158
- window.document.body.style.overflowY = 'auto'
1159
- },
1160
- };
1161
- return (
1162
- <>
1163
- <Button
1164
- label="Launch modal with default scroll prevention"
1165
- onClick={() => setModalOpen(1)}
1166
- />
1167
- <Button
1168
- label="Launch modal with no scroll prevention"
1169
- onClick={() => setModalOpen(2)}
1170
- />
1171
- <Button
1172
- label="Launch modal with custom scroll prevention"
1173
- onClick={() => setModalOpen(3)}
1174
- />
1175
- <div>
1176
- {modalOpen === 1 && (
1177
- <Modal
1178
- closeButtonRef={modalCloseButtonRef}
1179
- primaryButtonRef={modalPrimaryButtonRef}
1180
- >
1181
- <ModalHeader>
1182
- <ModalTitle>Modal with default scroll prevention</ModalTitle>
1183
- <ModalCloseButton onClick={() => setModalOpen(null)} />
1184
- </ModalHeader>
1185
- <ModalBody>
1186
- <ModalContent>
1187
- <p>
1188
- This Modal uses default scroll prevention on the document's
1189
- <code>body</code> element.
1190
- </p>
1191
- </ModalContent>
1192
- </ModalBody>
1193
- <ModalFooter>
1194
- <Button
1195
- label="Acknowledge"
1196
- onClick={() => setModalOpen(null)}
1197
- ref={modalPrimaryButtonRef}
1198
- />
1199
- <Button
1200
- color="secondary"
1201
- label="Close"
1202
- onClick={() => setModalOpen(null)}
1203
- priority="outline"
1204
- ref={modalCloseButtonRef}
1205
- />
1206
- </ModalFooter>
1207
- </Modal>
1208
- )}
1209
- {modalOpen === 2 && (
1210
- <Modal
1211
- closeButtonRef={modalCloseButtonRef}
1212
- preventScrollUnderneath="off"
1213
- primaryButtonRef={modalPrimaryButtonRef}
1214
- >
1215
- <ModalHeader>
1216
- <ModalTitle>Modal with no scroll prevention</ModalTitle>
1217
- <ModalCloseButton onClick={() => setModalOpen(null)} />
1218
- </ModalHeader>
1219
- <ModalBody>
1220
- <ModalContent>
1221
- <p>
1222
- This Modal does not prevent scrolling.
1223
- </p>
1224
- </ModalContent>
1225
- </ModalBody>
1226
- <ModalFooter>
1227
- <Button
1228
- label="Acknowledge"
1229
- onClick={() => setModalOpen(null)}
1230
- ref={modalPrimaryButtonRef}
1231
- />
1232
- <Button
1233
- color="secondary"
1234
- label="Close"
1235
- onClick={() => setModalOpen(null)}
1236
- priority="outline"
1237
- ref={modalCloseButtonRef}
1238
- />
1239
- </ModalFooter>
1240
- </Modal>
1241
- )}
1242
- {modalOpen === 3 && (
1243
- <Modal
1244
- closeButtonRef={modalCloseButtonRef}
1245
- preventScrollUnderneath={customScrollPreventionObject}
1246
- primaryButtonRef={modalPrimaryButtonRef}
1247
- >
1248
- <ModalHeader>
1249
- <ModalTitle>Modal with custom scroll prevention</ModalTitle>
1250
- <ModalCloseButton onClick={() => setModalOpen(null)} />
1251
- </ModalHeader>
1252
- <ModalBody>
1253
- <ModalContent>
1254
- <p>
1255
- This Modal uses provided custom functions to prevent scrolling
1256
- and reset it on unmount.
1257
- </p>
1258
- </ModalContent>
1259
- </ModalBody>
1260
- <ModalFooter>
1261
- <Button
1262
- label="Acknowledge"
1263
- onClick={() => setModalOpen(null)}
1264
- ref={modalPrimaryButtonRef}
1265
- />
1266
- <Button
1267
- color="secondary"
1268
- label="Close"
1269
- onClick={() => setModalOpen(null)}
1270
- priority="outline"
1271
- ref={modalCloseButtonRef}
1272
- />
1273
- </ModalFooter>
1274
- </Modal>
1275
- )}
1276
- </div>
1277
- </>
1278
- );
1279
- }}
1280
- </Playground>
1281
-
1282
- <!-- markdownlint-disable MD024 -->
1283
-
1284
- ## Forwarding HTML Attributes
1285
-
1286
- In addition to the options below in the [component's API](#api) section, you
1287
- can specify [React synthetic events] or **any HTML attribute you like.** All
1288
- attributes that don't interfere with the API are forwarded to the:
1289
-
1290
- - `<div>` HTML element in case of the `Modal` component. This `<div>` is not the
1291
- root, but its first child which represents the modal window.
1292
- - root `<div>` HTML element in case of `ModalHeader`, `ModalBody`, `ModalContent`
1293
- and `ModalFooter` components.
1294
- - heading HTML element, which level can be specified through `level` option, in
1295
- case of the `ModalTitle` component.
1296
- - native HTML `<button>` in case of the `ModalCloseButton` component.
1297
-
1298
- This enables making the component interactive and helps to improve its
1299
- accessibility.
1300
-
1301
- 👉 Refer to the MDN reference for the full list of supported attributes of the
1302
- [div], [heading] and [button] element.
1303
-
1304
- ## API
1305
-
1306
- <Props table of={Modal} />
1307
-
1308
- ### ModalHeader
1309
-
1310
- <Props table of={ModalHeader} />
1311
-
1312
- ### ModalTitle
1313
-
1314
- <Props table of={ModalTitle} />
1315
-
1316
- ### ModalCloseButton
1317
-
1318
- <Props table of={ModalCloseButton} />
1319
-
1320
- ### ModalBody
1321
-
1322
- <Props table of={ModalBody} />
1323
-
1324
- ### ModalContent
1325
-
1326
- <Props table of={ModalContent} />
1327
-
1328
- ### ModalFooter
1329
-
1330
- <Props table of={ModalFooter} />
1331
-
1332
- ## Theming
1333
-
1334
- | Custom Property | Description |
1335
- |------------------------------------------------------|---------------------------------------------------------------|
1336
- | `--rui-Modal__padding-x` | Inline padding of individual modal components |
1337
- | `--rui-Modal__padding-y` | Block padding of individual modal components |
1338
- | `--rui-Modal__background` | Modal background (including `url()` or gradient) |
1339
- | `--rui-Modal__box-shadow` | Modal box shadow |
1340
- | `--rui-Modal__separator__width` | Width of separator between modal header, body, and footer |
1341
- | `--rui-Modal__separator__color` | Color of separator between modal header, body, and footer |
1342
- | `--rui-Modal__outer-spacing-xs` | Spacing around modal, `xs` screen size |
1343
- | `--rui-Modal__outer-spacing-sm` | Spacing around modal, `sm` screen size and bigger |
1344
- | `--rui-Modal__header__gap` | Modal header gap between children |
1345
- | `--rui-Modal__footer__background` | Modal footer background (including `url()` or gradient) |
1346
- | `--rui-Modal__footer__gap` | Modal footer gap between children |
1347
- | `--rui-Modal__backdrop__background` | Modal backdrop background (including `url()` or gradient) |
1348
- | `--rui-Modal--auto__min-width` | Min width of auto-sized modal (when enough screen estate) |
1349
- | `--rui-Modal--auto__max-width` | Max width of auto-sized modal (when enough screen estate) |
1350
- | `--rui-Modal--small__width` | Width of small modal |
1351
- | `--rui-Modal--medium__width` | Width of medium modal |
1352
- | `--rui-Modal--large__width` | Width of large modal |
1353
- | `--rui-Modal--fullscreen__width` | Width of fullscreen modal |
1354
- | `--rui-Modal--fullscreen__height` | Height of fullscreen modal |
1355
-
1356
- [nng-modal]: https://www.nngroup.com/articles/modal-nonmodal-dialog/
1357
- [React synthetic events]: https://reactjs.org/docs/events.html
1358
- [div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
1359
- [heading]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#attributes
1360
- [button]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes