@react-ui-org/react-ui 0.52.0 → 0.53.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. package/CODEOWNERS +23 -0
  2. package/README.md +10 -7
  3. package/dist/react-ui.css +42 -0
  4. package/dist/react-ui.js +1 -0
  5. package/package.json +64 -77
  6. package/src/{lib/components → components}/Alert/Alert.jsx +1 -1
  7. package/src/{lib/components/Alert/README.mdx → components/Alert/README.md} +84 -100
  8. package/src/{lib/components → components}/Badge/Badge.jsx +1 -1
  9. package/src/{lib/components → components}/Badge/Badge.scss +1 -1
  10. package/src/components/Badge/README.md +103 -0
  11. package/src/{lib/components → components}/Button/Button.jsx +1 -1
  12. package/src/components/Button/README.md +580 -0
  13. package/src/{lib/components → components}/ButtonGroup/ButtonGroup.jsx +11 -9
  14. package/src/{lib/components/ButtonGroup/README.mdx → components/ButtonGroup/README.md} +128 -134
  15. package/src/{lib/components → components}/Card/Card.jsx +1 -1
  16. package/src/components/Card/README.md +314 -0
  17. package/src/{lib/components/CheckboxField/README.mdx → components/CheckboxField/README.md} +96 -108
  18. package/src/{lib/components/FileInputField/README.mdx → components/FileInputField/README.md} +83 -95
  19. package/src/{lib/components → components}/FormLayout/FormLayout.jsx +4 -4
  20. package/src/components/FormLayout/README.md +462 -0
  21. package/src/{lib/components → components}/Grid/Grid.jsx +2 -2
  22. package/src/components/Grid/README.md +281 -0
  23. package/src/{lib/components → components}/InputGroup/InputGroup.jsx +20 -19
  24. package/src/{lib/components → components}/InputGroup/InputGroup.scss +1 -6
  25. package/src/{lib/components/InputGroup/README.mdx → components/InputGroup/README.md} +145 -163
  26. package/src/{lib/components → components}/Modal/Modal.jsx +6 -6
  27. package/src/components/Modal/README.md +1090 -0
  28. package/src/components/Modal/_hooks/useModalScrollPrevention.js +37 -0
  29. package/src/{lib/components/Paper/README.mdx → components/Paper/README.md} +18 -30
  30. package/src/{lib/components/Popover/README.mdx → components/Popover/README.md} +102 -132
  31. package/src/{lib/components/Radio/README.mdx → components/Radio/README.md} +122 -134
  32. package/src/{lib/components → components}/Radio/Radio.jsx +11 -12
  33. package/src/{lib/components → components}/Radio/Radio.scss +1 -6
  34. package/src/components/ScrollView/README.md +503 -0
  35. package/src/{lib/components → components}/ScrollView/ScrollView.jsx +12 -3
  36. package/src/components/SelectField/README.md +681 -0
  37. package/src/components/Table/README.md +259 -0
  38. package/src/{lib/components → components}/Table/Table.jsx +4 -1
  39. package/src/{lib/components → components}/Table/_components/TableHeaderCell/TableHeaderCell.jsx +1 -1
  40. package/src/{lib/components/Tabs/README.mdx → components/Tabs/README.md} +117 -134
  41. package/src/{lib/components → components}/Tabs/TabsItem.jsx +3 -3
  42. package/src/components/Text/README.md +220 -0
  43. package/src/components/TextArea/README.md +359 -0
  44. package/src/{lib/components/TextField/README.mdx → components/TextField/README.md} +336 -342
  45. package/src/{lib/components/TextLink/README.mdx → components/TextLink/README.md} +19 -31
  46. package/src/{lib/components/Toggle/README.mdx → components/Toggle/README.md} +98 -110
  47. package/src/components/Toolbar/README.md +359 -0
  48. package/src/{lib/components → components}/Toolbar/_helpers/getAlignClassName.js +12 -4
  49. package/src/components/_helpers/getRootPriorityClassName.js +15 -0
  50. package/src/{lib/index.js → index.js} +6 -0
  51. package/src/{lib/provider → provider}/RUIProvider.jsx +17 -11
  52. package/src/{lib/styles → styles}/tools/_caret.scss +1 -1
  53. package/src/{lib/styles → styles}/tools/form-fields/_box-field-elements.scss +1 -1
  54. package/src/{lib/styles → styles}/tools/form-fields/_box-field-layout.scss +26 -14
  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-sizes.scss +0 -0
  256. /package/src/{lib/styles → styles}/tools/form-fields/_foundation.scss +0 -0
  257. /package/src/{lib/styles → styles}/tools/form-fields/_inline-field-layout.scss +0 -0
  258. /package/src/{lib/styles → styles}/tools/form-fields/_variants.scss +0 -0
  259. /package/src/{lib/translations → translations}/en.js +0 -0
  260. /package/src/{lib/utils → utils}/classNames.js +0 -0
@@ -0,0 +1,1090 @@
1
+ # Modal
2
+
3
+ Modal allows prompting users to take or complete an action.
4
+
5
+ ## Basic Usage
6
+
7
+ To implement the Modal component, you need to import it first:
8
+
9
+ ```js
10
+ import {
11
+ Modal,
12
+ ModalBody,
13
+ ModalCloseButton,
14
+ ModalContent,
15
+ ModalFooter,
16
+ ModalHeader,
17
+ ModalTitle,
18
+ } from '@react-ui-org/react-ui';
19
+ ```
20
+
21
+ And use it:
22
+
23
+ ```docoff-react-preview
24
+ React.createElement(() => {
25
+ const [modalOpen, setModalOpen] = React.useState(false);
26
+ const modalPrimaryButtonRef = React.useRef();
27
+ const modalCloseButtonRef = React.useRef();
28
+ {/*
29
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
30
+ React UI docs. You may not need it in your application.
31
+ */}
32
+ return (
33
+ <RUIProvider globalProps={{
34
+ Modal: { preventScrollUnderneath: window.document.documentElement }
35
+ }}>
36
+ <Button
37
+ label="Launch modal"
38
+ onClick={() => setModalOpen(true)}
39
+ />
40
+ <div>
41
+ {modalOpen && (
42
+ <Modal
43
+ closeButtonRef={modalCloseButtonRef}
44
+ primaryButtonRef={modalPrimaryButtonRef}
45
+ >
46
+ <ModalHeader>
47
+ <ModalTitle>Delete the user?</ModalTitle>
48
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
49
+ </ModalHeader>
50
+ <ModalBody>
51
+ <ModalContent>
52
+ <p>
53
+ Do you really want to delete the user <code>admin</code>?
54
+ This cannot be undone.
55
+ </p>
56
+ </ModalContent>
57
+ </ModalBody>
58
+ <ModalFooter>
59
+ <Button
60
+ color="danger"
61
+ label="Delete"
62
+ onClick={() => setModalOpen(false)}
63
+ ref={modalPrimaryButtonRef}
64
+ />
65
+ <Button
66
+ label="Close"
67
+ onClick={() => setModalOpen(false)}
68
+ priority="outline"
69
+ ref={modalCloseButtonRef}
70
+ />
71
+ </ModalFooter>
72
+ </Modal>
73
+ )}
74
+ </div>
75
+ </RUIProvider>
76
+ );
77
+ });
78
+ ```
79
+
80
+ See [API](#api) for all available options.
81
+
82
+ ## General Guidelines
83
+
84
+ - Use modals to **confirm an action,** display a **blocking alert**, or reveal
85
+ **contextual options or settings** that cannot be displayed in line with the
86
+ parent content.
87
+
88
+ - **The title** should communicate the **purpose of the modal** rather than a
89
+ generic text. For example “Delete the user?” tells more than “Are you sure?” or
90
+ “Warning”.
91
+
92
+ - **Modal actions** should correspond to the modal purpose, too. E.g. “Delete”
93
+ tells better what happens rather than “OK”.
94
+
95
+ - Modal **automatically focuses the first non-disabled form field** by default
96
+ which allows users to confirm the modal by hitting the enter key. When no
97
+ field is found then the primary button (in the footer) is focused. To turn
98
+ this feature off, set the `autofocus` prop to `false`.
99
+
100
+ - **Avoid stacking** of modals. While it may technically work, the modal is just
101
+ not designed for that.
102
+
103
+ ## Composition
104
+
105
+ Modal is decomposed into the following components:
106
+
107
+ - Modal
108
+ - [ModalHeader](#modalheader)
109
+ - ModalTitle
110
+ - ModalCloseButton
111
+ - [ModalBody](#modalbody)
112
+ - ModalContent
113
+ (may be wrapped with [ScrollView](/components/ScrollView))
114
+ - [ModalFooter](#modalfooter)
115
+
116
+ Using different combinations, you can compose different kinds of modals,
117
+ e.g. dialog modal, blocking modal, scrollable modal, etc.
118
+
119
+ ```docoff-react-preview
120
+ React.createElement(() => {
121
+ const [modalOpen, setModalOpen] = React.useState(null);
122
+ const modalPrimaryButtonRef = React.useRef();
123
+ const modalCloseButtonRef = React.useRef();
124
+ {/*
125
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
126
+ React UI docs. You may not need it in your application.
127
+ */}
128
+ return (
129
+ <RUIProvider globalProps={{
130
+ Modal: { preventScrollUnderneath: window.document.documentElement }
131
+ }}>
132
+ <Button
133
+ label="Launch blocking modal without title"
134
+ onClick={() => {
135
+ setModalOpen(1);
136
+ setTimeout(() => setModalOpen(null), 2500);
137
+ }}
138
+ />
139
+ <Button
140
+ label="Launch blocking modal with title"
141
+ onClick={() => {
142
+ setModalOpen(2);
143
+ setTimeout(() => setModalOpen(null), 3500);
144
+ }}
145
+ />
146
+ <Button
147
+ label="Launch modal as dialog"
148
+ onClick={() => setModalOpen(3)}
149
+ />
150
+ <Button
151
+ label="Launch modal as form"
152
+ onClick={() => setModalOpen(4)}
153
+ />
154
+ <div>
155
+ {modalOpen === 1 && (
156
+ <Modal>
157
+ <ModalBody>
158
+ <ModalContent>
159
+ <p className="text-center">
160
+ Application is being loaded.
161
+ <span className="d-inline-flex align-items-center animation-spin-counterclockwise">
162
+ <rui-icon icon="loading" />
163
+ </span>
164
+ </p>
165
+ </ModalContent>
166
+ </ModalBody>
167
+ </Modal>
168
+ )}
169
+ {modalOpen === 2 && (
170
+ <Modal>
171
+ <ModalHeader>
172
+ <ModalTitle>Action finished</ModalTitle>
173
+ </ModalHeader>
174
+ <ModalBody>
175
+ <ModalContent>
176
+ <p>
177
+ Action has been successfully finished.
178
+ You will be redirected within a few seconds.
179
+ </p>
180
+ </ModalContent>
181
+ </ModalBody>
182
+ </Modal>
183
+ )}
184
+ {modalOpen === 3 && (
185
+ <Modal
186
+ closeButtonRef={modalCloseButtonRef}
187
+ primaryButtonRef={modalPrimaryButtonRef}
188
+ >
189
+ <ModalHeader>
190
+ <ModalTitle>Delete the user?</ModalTitle>
191
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
192
+ </ModalHeader>
193
+ <ModalBody>
194
+ <ModalContent>
195
+ <p>
196
+ Do you really want to delete the user <code>admin</code>?
197
+ This cannot be undone.
198
+ </p>
199
+ </ModalContent>
200
+ </ModalBody>
201
+ <ModalFooter>
202
+ <Button
203
+ color="danger"
204
+ label="Delete"
205
+ onClick={() => setModalOpen(false)}
206
+ ref={modalPrimaryButtonRef}
207
+ />
208
+ <Button
209
+ label="Close"
210
+ onClick={() => setModalOpen(false)}
211
+ priority="outline"
212
+ ref={modalCloseButtonRef}
213
+ />
214
+ </ModalFooter>
215
+ </Modal>
216
+ )}
217
+ {modalOpen === 4 && (
218
+ <Modal
219
+ closeButtonRef={modalCloseButtonRef}
220
+ primaryButtonRef={modalPrimaryButtonRef}
221
+ >
222
+ <ModalHeader>
223
+ <ModalTitle>Add new user</ModalTitle>
224
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
225
+ </ModalHeader>
226
+ <ModalBody>
227
+ <ModalContent>
228
+ <FormLayout fieldLayout="horizontal">
229
+ <TextField label="Username" />
230
+ <TextField label="Password" type="password" />
231
+ </FormLayout>
232
+ </ModalContent>
233
+ </ModalBody>
234
+ <ModalFooter>
235
+ <Button
236
+ label="Save"
237
+ onClick={() => setModalOpen(false)}
238
+ ref={modalPrimaryButtonRef}
239
+ />
240
+ <Button
241
+ label="Close"
242
+ onClick={() => setModalOpen(false)}
243
+ priority="outline"
244
+ ref={modalCloseButtonRef}
245
+ />
246
+ </ModalFooter>
247
+ </Modal>
248
+ )}
249
+ </div>
250
+ </RUIProvider>
251
+ );
252
+ });
253
+ ```
254
+
255
+ ### ModalHeader
256
+
257
+ ModalHeader is an optional part of the Modal which allows you to display the title
258
+ of the modal and its close button.
259
+
260
+ It is recommended to compose ModalHeader from the following elements. For title,
261
+ use ModalTitle. For the close button, use ModalCloseButton, however it can
262
+ be omitted if a close button is part of ModalFooter.
263
+
264
+ There are two ways how to position elements within the ModalHeader:
265
+
266
+ 1. You can use provided positioning. Place previously mentioned elements into
267
+ the ModalHeader and use `justify` prop to set up the positioning of those
268
+ elements.
269
+ 2. You can customize positioning using another component (e.g.
270
+ [Toolbar](/components/Toolbar)). In that case, set `justify` to `stretch` and
271
+ position elements on your own.
272
+
273
+ ```docoff-react-preview
274
+ React.createElement(() => {
275
+ const [modalOpen, setModalOpen] = React.useState(false);
276
+ const [variant, setVariant] = React.useState(null);
277
+ const modalPrimaryButtonRef = React.useRef();
278
+ const modalCloseButtonRef = React.useRef();
279
+ {/*
280
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
281
+ React UI docs. You may not need it in your application.
282
+ */}
283
+ return (
284
+ <RUIProvider globalProps={{
285
+ Modal: { preventScrollUnderneath: window.document.documentElement }
286
+ }}>
287
+ <Button
288
+ label="Launch with close button"
289
+ onClick={() => {
290
+ setModalOpen(true);
291
+ setVariant(1);
292
+ }}
293
+ />
294
+ <Button
295
+ label="Launch without close button"
296
+ onClick={() => {
297
+ setModalOpen(true);
298
+ setVariant(2);
299
+ }}
300
+ />
301
+ <Button
302
+ label="Launch without close button and with centered title"
303
+ onClick={() => {
304
+ setModalOpen(true);
305
+ setVariant(3);
306
+ }}
307
+ />
308
+ <Button
309
+ label="Launch with custom layout"
310
+ onClick={() => {
311
+ setModalOpen(true);
312
+ setVariant(4);
313
+ }}
314
+ />
315
+ <div>
316
+ {modalOpen && (
317
+ <Modal
318
+ closeButtonRef={modalCloseButtonRef}
319
+ primaryButtonRef={modalPrimaryButtonRef}
320
+ >
321
+ {variant === 1 && (
322
+ <ModalHeader>
323
+ <ModalTitle>Delete the user?</ModalTitle>
324
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
325
+ </ModalHeader>
326
+ )}
327
+ {variant === 2 && (
328
+ <ModalHeader>
329
+ <ModalTitle>Delete the user?</ModalTitle>
330
+ </ModalHeader>
331
+ )}
332
+ {variant === 3 && (
333
+ <ModalHeader justify="center">
334
+ <ModalTitle>Delete the user?</ModalTitle>
335
+ </ModalHeader>
336
+ )}
337
+ {variant === 4 && (
338
+ <ModalHeader justify="stretch">
339
+ <Toolbar justify="space-between">
340
+ <ToolbarItem>
341
+ {''}
342
+ </ToolbarItem>
343
+ <ToolbarItem>
344
+ <ModalTitle>Delete the user?</ModalTitle>
345
+ </ToolbarItem>
346
+ <ToolbarItem>
347
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
348
+ </ToolbarItem>
349
+ </Toolbar>
350
+ </ModalHeader>
351
+ )}
352
+ <ModalBody>
353
+ <ModalContent>
354
+ <p>
355
+ Do you really want to delete the user <code>admin</code>?
356
+ This cannot be undone.
357
+ </p>
358
+ </ModalContent>
359
+ </ModalBody>
360
+ <ModalFooter>
361
+ <Button
362
+ color="danger"
363
+ label="Delete"
364
+ onClick={() => setModalOpen(false)}
365
+ ref={modalPrimaryButtonRef}
366
+ />
367
+ <Button
368
+ label="Close"
369
+ onClick={() => setModalOpen(false)}
370
+ priority="outline"
371
+ ref={modalCloseButtonRef}
372
+ />
373
+ </ModalFooter>
374
+ </Modal>
375
+ )}
376
+ </div>
377
+ </RUIProvider>
378
+ );
379
+ });
380
+ ```
381
+
382
+ ### ModalBody
383
+
384
+ ModalBody is a mandatory part of the Modal which allows you to display the
385
+ content of the Modal.
386
+
387
+ Although the ModalBody allows you to display arbitrary content, you should not
388
+ place content directly into the ModalBody, but wrap it with ModalContent first.
389
+
390
+ In case your content is expected to be long, consider wrapping ModalContent
391
+ with ScrollView. Check [Scrolling Long Content](#scrolling-long-content) section
392
+ below.
393
+
394
+ ### ModalFooter
395
+
396
+ ModalFooter is an optional part of the Modal which allows you to display
397
+ user actions.
398
+
399
+ There are two ways to position buttons within the ModalFooter:
400
+
401
+ 1. You can use provided positioning. Place Button component (or any arbitrary
402
+ element) and use `justify` prop to set up the positioning of those elements.
403
+ 2. You can customize positioning using another component (e.g.
404
+ [Toolbar](/components/Toolbar)). In that case, set `justify` to `stretch`
405
+ and position elements on your own.
406
+
407
+ ```docoff-react-preview
408
+ React.createElement(() => {
409
+ const [modalOpen, setModalOpen] = React.useState(false);
410
+ const [modalJustify, setModalJustify] = React.useState('center');
411
+ const modalPrimaryButtonRef = React.useRef();
412
+ const modalCloseButtonRef = React.useRef();
413
+ {/*
414
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
415
+ React UI docs. You may not need it in your application.
416
+ */}
417
+ return (
418
+ <RUIProvider globalProps={{
419
+ Modal: { preventScrollUnderneath: window.document.documentElement }
420
+ }}>
421
+ <Button
422
+ label="Launch modal with footer variants"
423
+ onClick={() => setModalOpen(true)}
424
+ />
425
+ <div>
426
+ {modalOpen && (
427
+ <Modal
428
+ closeButtonRef={modalCloseButtonRef}
429
+ primaryButtonRef={modalPrimaryButtonRef}
430
+ >
431
+ <ModalHeader>
432
+ <ModalTitle>Footer justification</ModalTitle>
433
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
434
+ </ModalHeader>
435
+ <ModalBody>
436
+ <ModalContent>
437
+ <Radio
438
+ label="Footer justification"
439
+ onChange={(e) => setModalJustify(e.target.value)}
440
+ options={[
441
+ {
442
+ label: 'start',
443
+ value: 'start',
444
+ },
445
+ {
446
+ label: 'center',
447
+ value: 'center',
448
+ },
449
+ {
450
+ label: 'end',
451
+ value: 'end',
452
+ },
453
+ {
454
+ label: 'space-between',
455
+ value: 'space-between',
456
+ },
457
+ {
458
+ label: 'stretch (with a custom layout)',
459
+ value: 'stretch',
460
+ },
461
+ ]}
462
+ value={modalJustify}
463
+ />
464
+ </ModalContent>
465
+ </ModalBody>
466
+ <ModalFooter justify={modalJustify}>
467
+ {
468
+ modalJustify === 'stretch'
469
+ ? (
470
+ <Toolbar justify="space-between">
471
+ <ToolbarGroup>
472
+ <ToolbarItem>
473
+ <Button
474
+ color="danger"
475
+ label="Delete"
476
+ onClick={() => setModalOpen(false)}
477
+ ref={modalPrimaryButtonRef}
478
+ />
479
+ </ToolbarItem>
480
+ <ToolbarItem>
481
+ <Button
482
+ color="warning"
483
+ label="Archive"
484
+ onClick={() => setModalOpen(false)}
485
+ ref={modalPrimaryButtonRef}
486
+ />
487
+ </ToolbarItem>
488
+ </ToolbarGroup>
489
+ <ToolbarItem>
490
+ <Button
491
+ color="secondary"
492
+ label="Close"
493
+ onClick={() => setModalOpen(false)}
494
+ priority="outline"
495
+ ref={modalCloseButtonRef}
496
+ />
497
+ </ToolbarItem>
498
+ </Toolbar>
499
+ ) : (
500
+ <>
501
+ <Button
502
+ label="OK"
503
+ onClick={() => setModalOpen(false)}
504
+ ref={modalPrimaryButtonRef}
505
+ />
506
+ <Button
507
+ color="secondary"
508
+ label="Close"
509
+ onClick={() => setModalOpen(false)}
510
+ priority="outline"
511
+ ref={modalCloseButtonRef}
512
+ />
513
+ </>
514
+ )
515
+ }
516
+ </ModalFooter>
517
+ </Modal>
518
+ )}
519
+ </div>
520
+ </RUIProvider>
521
+ );
522
+ });
523
+ ```
524
+
525
+ ## Sizes
526
+
527
+ Modal is available in three fixed-width sizes: small, medium, large and fullscreen.
528
+ Modals of any size automatically shrink when they cannot fit the screen width.
529
+
530
+ ```docoff-react-preview
531
+ React.createElement(() => {
532
+ const [modalOpen, setModalOpen] = React.useState(false);
533
+ const [modalSize, setModalSize] = React.useState('small');
534
+ const modalPrimaryButtonRef = React.useRef();
535
+ const modalCloseButtonRef = React.useRef();
536
+ {/*
537
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
538
+ React UI docs. You may not need it in your application.
539
+ */}
540
+ return (
541
+ <RUIProvider globalProps={{
542
+ Modal: { preventScrollUnderneath: window.document.documentElement }
543
+ }}>
544
+ <Button
545
+ label="Launch small modal"
546
+ onClick={() => {
547
+ setModalSize('small');
548
+ setModalOpen(true);
549
+ }}
550
+ />
551
+ <Button
552
+ label="Launch medium modal"
553
+ onClick={() => {
554
+ setModalSize('medium');
555
+ setModalOpen(true);
556
+ }}
557
+ />
558
+ <Button
559
+ label="Launch large modal"
560
+ onClick={() => {
561
+ setModalSize('large');
562
+ setModalOpen(true);
563
+ }}
564
+ />
565
+ <Button
566
+ label="Launch fullscreen modal"
567
+ onClick={() => {
568
+ setModalSize('fullscreen');
569
+ setModalOpen(true);
570
+ }}
571
+ />
572
+ <div>
573
+ {modalOpen && (
574
+ <Modal
575
+ closeButtonRef={modalCloseButtonRef}
576
+ primaryButtonRef={modalPrimaryButtonRef}
577
+ size={modalSize}
578
+ >
579
+ <ModalHeader>
580
+ <ModalTitle>Delete the user?</ModalTitle>
581
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
582
+ </ModalHeader>
583
+ <ModalBody>
584
+ <ModalContent>
585
+ <p>
586
+ Do you really want to delete the user <code>admin</code>?
587
+ This cannot be undone.
588
+ </p>
589
+ </ModalContent>
590
+ </ModalBody>
591
+ <ModalFooter>
592
+ <Button
593
+ color="danger"
594
+ label="Delete"
595
+ onClick={() => setModalOpen(false)}
596
+ ref={modalPrimaryButtonRef}
597
+ />
598
+ <Button
599
+ label="Close"
600
+ onClick={() => setModalOpen(false)}
601
+ priority="outline"
602
+ ref={modalCloseButtonRef}
603
+ />
604
+ </ModalFooter>
605
+ </Modal>
606
+ )}
607
+ </div>
608
+ </RUIProvider>
609
+ );
610
+ });
611
+ ```
612
+
613
+ On top of that, the modal can adjust to the width of its content.
614
+
615
+ ```docoff-react-preview
616
+ React.createElement(() => {
617
+ const [modalOpen, setModalOpen] = React.useState(false);
618
+ const modalPrimaryButtonRef = React.useRef();
619
+ const modalCloseButtonRef = React.useRef();
620
+ {/*
621
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
622
+ React UI docs. You may not need it in your application.
623
+ */}
624
+ return (
625
+ <RUIProvider globalProps={{
626
+ Modal: { preventScrollUnderneath: window.document.documentElement }
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
+ label="Close"
660
+ onClick={() => setModalOpen(false)}
661
+ priority="outline"
662
+ ref={modalCloseButtonRef}
663
+ />
664
+ </ModalFooter>
665
+ </Modal>
666
+ )}
667
+ </div>
668
+ </RUIProvider>
669
+ );
670
+ });
671
+ ```
672
+
673
+ 👉 Please note the auto width may not function correctly in combination with
674
+ other auto-layout mechanisms, e.g. the auto-width
675
+ [FormLayout](/components/FormLayout#label-width). It's just too much
676
+ magic that doesn't work together (yet?) 🎩.
677
+
678
+ 👉 Beware of horizontal FormLayout inside `small` modals. While automatic
679
+ overflow handling comes to the rescue in this kind of scenario, you will be
680
+ better off with the combination of auto-sized modal and horizontal FormLayout
681
+ with a fixed label width (i.e. any other than `auto`, see the previous note).
682
+
683
+ ```docoff-react-preview
684
+ React.createElement(() => {
685
+ const [modalOpen, setModalOpen] = React.useState(false);
686
+ const modalPrimaryButtonRef = React.useRef();
687
+ const modalCloseButtonRef = React.useRef();
688
+ {/*
689
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
690
+ React UI docs. You may not need it in your application.
691
+ */}
692
+ return (
693
+ <RUIProvider globalProps={{
694
+ Modal: { preventScrollUnderneath: window.document.documentElement }
695
+ }}>
696
+ <Button
697
+ label="Launch auto-with modal with a form"
698
+ onClick={() => setModalOpen(true)}
699
+ />
700
+ <div>
701
+ {modalOpen && (
702
+ <Modal
703
+ closeButtonRef={modalCloseButtonRef}
704
+ primaryButtonRef={modalPrimaryButtonRef}
705
+ size="auto"
706
+ >
707
+ <ModalHeader>
708
+ <ModalTitle>Form inside modal</ModalTitle>
709
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
710
+ </ModalHeader>
711
+ <ModalBody>
712
+ <ModalContent>
713
+ <FormLayout fieldLayout="horizontal">
714
+ <TextField label="A form element" />
715
+ <TextField label="Another form element" />
716
+ <TextField label="Yet another one" />
717
+ </FormLayout>
718
+ </ModalContent>
719
+ </ModalBody>
720
+ <ModalFooter>
721
+ <Button
722
+ color="primary"
723
+ label="Save"
724
+ onClick={() => setModalOpen(false)}
725
+ ref={modalPrimaryButtonRef}
726
+ />
727
+ <Button
728
+ label="Cancel"
729
+ onClick={() => setModalOpen(false)}
730
+ priority="outline"
731
+ ref={modalCloseButtonRef}
732
+ />
733
+ </ModalFooter>
734
+ </Modal>
735
+ )}
736
+ </div>
737
+ </RUIProvider>
738
+ );
739
+ });
740
+ ```
741
+
742
+ ## Position
743
+
744
+ Modal can be aligned either to the top or center of the screen.
745
+
746
+ ```docoff-react-preview
747
+ React.createElement(() => {
748
+ const [modalOpen, setModalOpen] = React.useState(false);
749
+ const [modalPosition, setModalPosition] = React.useState('center');
750
+ const modalPrimaryButtonRef = React.useRef();
751
+ const modalCloseButtonRef = React.useRef();
752
+ {/*
753
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
754
+ React UI docs. You may not need it in your application.
755
+ */}
756
+ return (
757
+ <RUIProvider globalProps={{
758
+ Modal: { preventScrollUnderneath: window.document.documentElement }
759
+ }}>
760
+ <Button
761
+ label="Launch modal at center"
762
+ onClick={() => {
763
+ setModalPosition('center');
764
+ setModalOpen(true);
765
+ }}
766
+ />
767
+ <Button
768
+ label="Launch modal at top"
769
+ onClick={() => {
770
+ setModalPosition('top');
771
+ setModalOpen(true);
772
+ }}
773
+ />
774
+ <div>
775
+ {modalOpen && (
776
+ <Modal
777
+ closeButtonRef={modalCloseButtonRef}
778
+ position={modalPosition}
779
+ primaryButtonRef={modalPrimaryButtonRef}
780
+ >
781
+ <ModalHeader>
782
+ <ModalTitle>Delete the user?</ModalTitle>
783
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
784
+ </ModalHeader>
785
+ <ModalBody>
786
+ <ModalContent>
787
+ <p>
788
+ Do you really want to delete the user <code>admin</code>?
789
+ This cannot be undone.
790
+ </p>
791
+ </ModalContent>
792
+ </ModalBody>
793
+ <ModalFooter>
794
+ <Button
795
+ color="danger"
796
+ label="Delete"
797
+ onClick={() => setModalOpen(false)}
798
+ ref={modalPrimaryButtonRef}
799
+ />
800
+ <Button
801
+ label="Close"
802
+ onClick={() => setModalOpen(false)}
803
+ priority="outline"
804
+ ref={modalCloseButtonRef}
805
+ />
806
+ </ModalFooter>
807
+ </Modal>
808
+ )}
809
+ </div>
810
+ </RUIProvider>
811
+ );
812
+ });
813
+ ```
814
+
815
+ ## Keyboard Control
816
+
817
+ Modal can be controlled either by mouse or keyboard. To enhance user
818
+ experience, primary action can be fired by pressing `Enter` key and the modal
819
+ can be closed by pressing the `Escape` key.
820
+
821
+ To enable it, you just need to pass a reference to the buttons using
822
+ `primaryButtonRef` and `closeButtonRef` props on Modal. The advantage of passing
823
+ a reference to the button is that if the button is disabled, the key press will
824
+ not fire the event.
825
+
826
+ 👉 We strongly recommend using this feature together with Autofocus for a better
827
+ user experience.
828
+
829
+ ## Autofocus
830
+
831
+ Autofocus is implemented to enhance the user experience by automatically
832
+ focussing an element within the modal.
833
+
834
+ How does it work? It tries to find `input`, `textarea`, and `select` elements
835
+ inside of Modal and moves focus onto the first non-disabled one. If none is
836
+ found and the `primaryButtonRef` prop on Modal is set, then the primary button
837
+ is focused.
838
+
839
+ Autofocus is enabled by default, so if you want to control the focus of
840
+ elements manually, set the `autoFocus` prop on Modal to `false`.
841
+
842
+ ## Scrolling Long Content
843
+
844
+ When modals become too long for the user's viewport or device, they scroll
845
+ independent of the page itself. This can be done in three ways using the
846
+ `scrolling` option of the ModalBody component:
847
+
848
+ - `auto` (default) — ModalBody is responsible for scrolling,
849
+ - `custom` — you must provide a custom component to handle scrolling,
850
+ typically an instance of [ScrollView](/components/ScrollView) wrapping
851
+ ModalContent,
852
+ - `none` — entire Modal is responsible for scrolling.
853
+
854
+ ```docoff-react-preview
855
+ React.createElement(() => {
856
+ const [modalOpen, setModalOpen] = React.useState(false);
857
+ const [modalScrolling, setModalScrolling] = React.useState('auto');
858
+ const modalCloseButtonRef = React.useRef();
859
+ const modalPrimaryButtonRef = React.useRef();
860
+ const modalContent = (
861
+ <ModalContent>
862
+ <p>
863
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
864
+ commodo ligula eget dolor. Aenean massa.
865
+ </p>
866
+ <p>
867
+ Cum sociis natoque penatibus et magnis dis parturient montes,
868
+ nascetur ridiculus mus. Donec quam felis, ultricies nec,
869
+ pellentesque eu, pretium quis, sem.
870
+ </p>
871
+ <p>
872
+ Nulla consequat massa quis enim. Donec pede justo, fringilla
873
+ vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
874
+ ut, imperdiet a, venenatis vitae, justo.
875
+ </p>
876
+ <p>
877
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
878
+ commodo ligula eget dolor. Aenean massa.
879
+ </p>
880
+ <p>
881
+ Cum sociis natoque penatibus et magnis dis parturient montes,
882
+ nascetur ridiculus mus. Donec quam felis, ultricies nec,
883
+ pellentesque eu, pretium quis, sem.
884
+ </p>
885
+ <p>
886
+ Nulla consequat massa quis enim. Donec pede justo, fringilla
887
+ vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
888
+ ut, imperdiet a, venenatis vitae, justo.
889
+ </p>
890
+ <p>
891
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
892
+ commodo ligula eget dolor. Aenean massa.
893
+ </p>
894
+ <p>
895
+ Cum sociis natoque penatibus et magnis dis parturient montes,
896
+ nascetur ridiculus mus. Donec quam felis, ultricies nec,
897
+ pellentesque eu, pretium quis, sem.
898
+ </p>
899
+ <p>
900
+ Nulla consequat massa quis enim. Donec pede justo, fringilla
901
+ vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
902
+ ut, imperdiet a, venenatis vitae, justo.
903
+ </p>
904
+ <p>
905
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
906
+ commodo ligula eget dolor. Aenean massa.
907
+ </p>
908
+ <p>
909
+ Cum sociis natoque penatibus et magnis dis parturient montes,
910
+ nascetur ridiculus mus. Donec quam felis, ultricies nec,
911
+ pellentesque eu, pretium quis, sem.
912
+ </p>
913
+ <p>
914
+ Nulla consequat massa quis enim. Donec pede justo, fringilla
915
+ vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
916
+ ut, imperdiet a, venenatis vitae, justo.
917
+ </p>
918
+ <p>
919
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
920
+ commodo ligula eget dolor. Aenean massa.
921
+ </p>
922
+ <p>
923
+ Cum sociis natoque penatibus et magnis dis parturient montes,
924
+ nascetur ridiculus mus. Donec quam felis, ultricies nec,
925
+ pellentesque eu, pretium quis, sem.
926
+ </p>
927
+ <p>
928
+ Nulla consequat massa quis enim. Donec pede justo, fringilla
929
+ vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus
930
+ ut, imperdiet a, venenatis vitae, justo.
931
+ </p>
932
+ </ModalContent>
933
+ );
934
+ {/*
935
+ The `preventScrollUnderneath` feature is necessary for Modals to work in
936
+ React UI docs. You may not need it in your application.
937
+ */}
938
+ return (
939
+ <RUIProvider globalProps={{
940
+ Modal: { preventScrollUnderneath: window.document.documentElement }
941
+ }}>
942
+ <Button
943
+ label="Launch modal with scrolling body"
944
+ onClick={() => {
945
+ setModalScrolling('auto');
946
+ setModalOpen(true);
947
+ }}
948
+ />
949
+ <Button
950
+ label="Launch modal with ScrollView"
951
+ onClick={() => {
952
+ setModalScrolling('custom');
953
+ setModalOpen(true);
954
+ }}
955
+ />
956
+ <Button
957
+ label="Launch modal with non-scrolling body"
958
+ onClick={() => {
959
+ setModalScrolling('none');
960
+ setModalOpen(true);
961
+ }}
962
+ />
963
+ <div>
964
+ {modalOpen && (
965
+ <Modal
966
+ autoFocus={false}
967
+ closeButtonRef={modalCloseButtonRef}
968
+ primaryButtonRef={modalPrimaryButtonRef}
969
+ size="small"
970
+ >
971
+ <ModalHeader>
972
+ <ModalTitle>Modal with long content</ModalTitle>
973
+ <ModalCloseButton onClick={() => setModalOpen(false)} />
974
+ </ModalHeader>
975
+ <ModalBody scrolling={modalScrolling}>
976
+ {
977
+ modalScrolling === 'custom'
978
+ ? (
979
+ <ScrollView>
980
+ {modalContent}
981
+ </ScrollView>
982
+ )
983
+ : modalContent
984
+ }
985
+ </ModalBody>
986
+ <ModalFooter>
987
+ <Button
988
+ label="OK"
989
+ onClick={() => setModalOpen(false)}
990
+ ref={modalPrimaryButtonRef}
991
+ />
992
+ <Button
993
+ label="Close"
994
+ onClick={() => setModalOpen(false)}
995
+ priority="outline"
996
+ ref={modalCloseButtonRef}
997
+ />
998
+ </ModalFooter>
999
+ </Modal>
1000
+ )}
1001
+ </div>
1002
+ </RUIProvider>
1003
+ );
1004
+ });
1005
+ ```
1006
+
1007
+ ### Long Content and Autofocus
1008
+
1009
+ 👉 If you wrap ModalContent with ScrollView, you may want to turn `autoFocus`
1010
+ off to prevent the modal from scrolling to the end immediately after being
1011
+ opened.
1012
+
1013
+ <!-- markdownlint-disable MD024 -->
1014
+
1015
+ ## Forwarding HTML Attributes
1016
+
1017
+ In addition to the options below in the [component's API](#api) section, you
1018
+ can specify [React synthetic events] or **any HTML attribute you like.** All
1019
+ attributes that don't interfere with the API are forwarded to the:
1020
+
1021
+ - `<div>` HTML element in case of the `Modal` component. This `<div>` is not the
1022
+ root, but its first child which represents the modal window.
1023
+ - root `<div>` HTML element in case of `ModalHeader`, `ModalBody`, `ModalContent`
1024
+ and `ModalFooter` components.
1025
+ - heading HTML element, which level can be specified through `level` option, in
1026
+ case of the `ModalTitle` component.
1027
+ - native HTML `<button>` in case of the `ModalCloseButton` component.
1028
+
1029
+ This enables making the component interactive and helps to improve its
1030
+ accessibility.
1031
+
1032
+ 👉 Refer to the MDN reference for the full list of supported attributes of the
1033
+ [div], [heading] and [button] element.
1034
+
1035
+ ## API
1036
+
1037
+ <docoff-react-props src="/components/Modal/Modal.jsx"></docoff-react-props>
1038
+
1039
+ ### ModalHeader
1040
+
1041
+ <docoff-react-props src="/components/Modal/ModalHeader.jsx"></docoff-react-props>
1042
+
1043
+ ### ModalTitle
1044
+
1045
+ <docoff-react-props src="/components/Modal/ModalTitle.jsx"></docoff-react-props>
1046
+
1047
+ ### ModalCloseButton
1048
+
1049
+ <docoff-react-props src="/components/Modal/ModalCloseButton.jsx"></docoff-react-props>
1050
+
1051
+ ### ModalBody
1052
+
1053
+ <docoff-react-props src="/components/Modal/ModalBody.jsx"></docoff-react-props>
1054
+
1055
+ ### ModalContent
1056
+
1057
+ <docoff-react-props src="/components/Modal/ModalContent.jsx"></docoff-react-props>
1058
+
1059
+ ### ModalFooter
1060
+
1061
+ <docoff-react-props src="/components/Modal/ModalFooter.jsx"></docoff-react-props>
1062
+
1063
+ ## Theming
1064
+
1065
+ | Custom Property | Description |
1066
+ |------------------------------------------------------|---------------------------------------------------------------|
1067
+ | `--rui-Modal__padding-x` | Inline padding of individual modal components |
1068
+ | `--rui-Modal__padding-y` | Block padding of individual modal components |
1069
+ | `--rui-Modal__background` | Modal background (including `url()` or gradient) |
1070
+ | `--rui-Modal__box-shadow` | Modal box shadow |
1071
+ | `--rui-Modal__separator__width` | Width of separator between modal header, body, and footer |
1072
+ | `--rui-Modal__separator__color` | Color of separator between modal header, body, and footer |
1073
+ | `--rui-Modal__outer-spacing-xs` | Spacing around modal, `xs` screen size |
1074
+ | `--rui-Modal__outer-spacing-sm` | Spacing around modal, `sm` screen size and bigger |
1075
+ | `--rui-Modal__header__gap` | Modal header gap between children |
1076
+ | `--rui-Modal__footer__background` | Modal footer background (including `url()` or gradient) |
1077
+ | `--rui-Modal__footer__gap` | Modal footer gap between children |
1078
+ | `--rui-Modal__backdrop__background` | Modal backdrop background (including `url()` or gradient) |
1079
+ | `--rui-Modal--auto__min-width` | Min width of auto-sized modal (when enough screen estate) |
1080
+ | `--rui-Modal--auto__max-width` | Max width of auto-sized modal (when enough screen estate) |
1081
+ | `--rui-Modal--small__width` | Width of small modal |
1082
+ | `--rui-Modal--medium__width` | Width of medium modal |
1083
+ | `--rui-Modal--large__width` | Width of large modal |
1084
+ | `--rui-Modal--fullscreen__width` | Width of fullscreen modal |
1085
+ | `--rui-Modal--fullscreen__height` | Height of fullscreen modal |
1086
+
1087
+ [React synthetic events]: https://reactjs.org/docs/events.html
1088
+ [div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
1089
+ [heading]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#attributes
1090
+ [button]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes