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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/CODEOWNERS +23 -0
  2. package/README.md +10 -7
  3. package/dist/react-ui.css +5 -3
  4. package/dist/react-ui.js +1 -1
  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 +0 -5
  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 +0 -5
  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/_inline-field-elements.scss +2 -2
  55. package/src/{lib/theme.scss → theme.scss} +4 -3
  56. package/CONTRIBUTING.md +0 -137
  57. package/dist/lib.development.js +0 -3179
  58. package/dist/lib.js +0 -1
  59. package/public/racom.svg +0 -11
  60. package/src/lib/components/Badge/README.mdx +0 -126
  61. package/src/lib/components/Button/README.mdx +0 -581
  62. package/src/lib/components/Card/README.mdx +0 -326
  63. package/src/lib/components/FormLayout/README.mdx +0 -501
  64. package/src/lib/components/Grid/README.mdx +0 -299
  65. package/src/lib/components/Modal/README.mdx +0 -1360
  66. package/src/lib/components/Modal/_hooks/useModalScrollPrevention.js +0 -35
  67. package/src/lib/components/ScrollView/README.mdx +0 -521
  68. package/src/lib/components/SelectField/README.mdx +0 -693
  69. package/src/lib/components/Table/README.mdx +0 -275
  70. package/src/lib/components/Text/README.mdx +0 -241
  71. package/src/lib/components/TextArea/README.mdx +0 -366
  72. package/src/lib/components/Toolbar/README.mdx +0 -386
  73. package/src/{lib/components → components}/Alert/Alert.scss +0 -0
  74. package/src/{lib/components → components}/Alert/_settings.scss +0 -0
  75. package/src/{lib/components → components}/Alert/_theme.scss +0 -0
  76. package/src/{lib/components → components}/Alert/_tools.scss +0 -0
  77. package/src/{lib/components → components}/Alert/index.js +0 -0
  78. package/src/{lib/components → components}/Badge/index.js +0 -0
  79. package/src/{lib/components → components}/Button/Button.scss +0 -0
  80. package/src/{lib/components → components}/Button/_base.scss +0 -0
  81. package/src/{lib/components → components}/Button/_priorities.scss +0 -0
  82. package/src/{lib/components → components}/Button/_settings.scss +0 -0
  83. package/src/{lib/components → components}/Button/_theme.scss +0 -0
  84. package/src/{lib/components → components}/Button/_tools.scss +0 -0
  85. package/src/{lib/components → components}/Button/helpers/getRootLabelVisibilityClassName.js +0 -0
  86. package/src/{lib/components/_helpers → components/Button/helpers}/getRootPriorityClassName.js +0 -0
  87. package/src/{lib/components → components}/Button/index.js +0 -0
  88. package/src/{lib/components → components}/ButtonGroup/ButtonGroup.scss +0 -0
  89. package/src/{lib/components → components}/ButtonGroup/ButtonGroupContext.js +0 -0
  90. package/src/{lib/components → components}/ButtonGroup/_theme.scss +0 -0
  91. package/src/{lib/components → components}/ButtonGroup/index.js +0 -0
  92. package/src/{lib/components → components}/Card/Card.scss +0 -0
  93. package/src/{lib/components → components}/Card/CardBody.jsx +0 -0
  94. package/src/{lib/components → components}/Card/CardFooter.jsx +0 -0
  95. package/src/{lib/components → components}/Card/_theme.scss +0 -0
  96. package/src/{lib/components → components}/Card/_tools.scss +0 -0
  97. package/src/{lib/components → components}/Card/index.js +0 -0
  98. package/src/{lib/components → components}/CheckboxField/CheckboxField.jsx +0 -0
  99. package/src/{lib/components → components}/CheckboxField/CheckboxField.scss +0 -0
  100. package/src/{lib/components → components}/CheckboxField/index.js +0 -0
  101. package/src/{lib/components → components}/FileInputField/FileInputField.jsx +0 -0
  102. package/src/{lib/components → components}/FileInputField/FileInputField.scss +0 -0
  103. package/src/{lib/components → components}/FileInputField/index.js +0 -0
  104. package/src/{lib/components → components}/FormLayout/FormLayout.scss +0 -0
  105. package/src/{lib/components → components}/FormLayout/FormLayoutContext.js +0 -0
  106. package/src/{lib/components → components}/FormLayout/FormLayoutCustomField.jsx +4 -4
  107. package/src/{lib/components → components}/FormLayout/FormLayoutCustomField.scss +0 -0
  108. package/src/{lib/components → components}/FormLayout/_theme.scss +0 -0
  109. package/src/{lib/components → components}/FormLayout/index.js +0 -0
  110. package/src/{lib/components → components}/Grid/Grid.scss +0 -0
  111. package/src/{lib/components → components}/Grid/GridSpan.jsx +0 -0
  112. package/src/{lib/components → components}/Grid/_helpers/generateResponsiveCustomProperties.js +0 -0
  113. package/src/{lib/components → components}/Grid/_settings.scss +0 -0
  114. package/src/{lib/components → components}/Grid/_tools.scss +0 -0
  115. package/src/{lib/components → components}/Grid/index.js +0 -0
  116. package/src/{lib/components → components}/InputGroup/InputGroupContext.js +0 -0
  117. package/src/{lib/components → components}/InputGroup/_theme.scss +0 -0
  118. package/src/{lib/components → components}/InputGroup/index.js +0 -0
  119. package/src/{lib/components → components}/Modal/Modal.scss +0 -0
  120. package/src/{lib/components → components}/Modal/ModalBody.jsx +0 -0
  121. package/src/{lib/components → components}/Modal/ModalBody.scss +0 -0
  122. package/src/{lib/components → components}/Modal/ModalCloseButton.jsx +1 -1
  123. package/src/{lib/components → components}/Modal/ModalCloseButton.scss +0 -0
  124. package/src/{lib/components → components}/Modal/ModalContent.jsx +0 -0
  125. package/src/{lib/components → components}/Modal/ModalContent.scss +0 -0
  126. package/src/{lib/components → components}/Modal/ModalFooter.jsx +0 -0
  127. package/src/{lib/components → components}/Modal/ModalFooter.scss +0 -0
  128. package/src/{lib/components → components}/Modal/ModalHeader.jsx +0 -0
  129. package/src/{lib/components → components}/Modal/ModalHeader.scss +0 -0
  130. package/src/{lib/components → components}/Modal/ModalTitle.jsx +0 -0
  131. package/src/{lib/components → components}/Modal/ModalTitle.scss +0 -0
  132. package/src/{lib/components → components}/Modal/_helpers/getJustifyClassName.js +0 -0
  133. package/src/{lib/components → components}/Modal/_helpers/getPositionClassName.js +0 -0
  134. package/src/{lib/components → components}/Modal/_helpers/getScrollingClassName.js +0 -0
  135. package/src/{lib/components → components}/Modal/_helpers/getSizeClassName.js +0 -0
  136. package/src/{lib/components → components}/Modal/_hooks/useModalFocus.js +0 -0
  137. package/src/{lib/components → components}/Modal/_settings.scss +0 -0
  138. package/src/{lib/components → components}/Modal/_theme.scss +0 -0
  139. package/src/{lib/components → components}/Modal/index.js +0 -0
  140. package/src/{lib/components → components}/Paper/Paper.jsx +0 -0
  141. package/src/{lib/components → components}/Paper/Paper.scss +0 -0
  142. package/src/{lib/components → components}/Paper/_theme.scss +0 -0
  143. package/src/{lib/components → components}/Paper/index.js +0 -0
  144. package/src/{lib/components → components}/Popover/Popover.jsx +0 -0
  145. package/src/{lib/components → components}/Popover/Popover.scss +0 -0
  146. package/src/{lib/components → components}/Popover/PopoverWrapper.jsx +0 -0
  147. package/src/{lib/components → components}/Popover/PopoverWrapper.scss +0 -0
  148. package/src/{lib/components → components}/Popover/_helpers/getRootAlignmentClassName.js +0 -0
  149. package/src/{lib/components → components}/Popover/_helpers/getRootSideClassName.js +0 -0
  150. package/src/{lib/components → components}/Popover/_theme.scss +0 -0
  151. package/src/{lib/components → components}/Popover/index.js +0 -0
  152. package/src/{lib/components → components}/Radio/index.js +0 -0
  153. package/src/{lib/components → components}/ScrollView/ScrollView.scss +0 -0
  154. package/src/{lib/components → components}/ScrollView/_helpers/getElementsPositionDifference.js +0 -0
  155. package/src/{lib/components → components}/ScrollView/_hooks/useLoadResizeHook.js +0 -0
  156. package/src/{lib/components → components}/ScrollView/_hooks/useScrollPositionHook.js +0 -0
  157. package/src/{lib/components → components}/ScrollView/index.js +0 -0
  158. package/src/{lib/components → components}/SelectField/SelectField.jsx +0 -0
  159. package/src/{lib/components → components}/SelectField/SelectField.scss +0 -0
  160. package/src/{lib/components → components}/SelectField/_components/Option/Option.jsx +0 -0
  161. package/src/{lib/components → components}/SelectField/_components/Option/index.js +0 -0
  162. package/src/{lib/components → components}/SelectField/index.js +0 -0
  163. package/src/{lib/components → components}/Table/Table.scss +0 -0
  164. package/src/{lib/components → components}/Table/_components/TableBodyCell/TableBodyCell.jsx +0 -0
  165. package/src/{lib/components → components}/Table/_components/TableBodyCell/index.js +0 -0
  166. package/src/{lib/components → components}/Table/_components/TableCell.scss +0 -0
  167. package/src/{lib/components → components}/Table/_components/TableHeaderCell/index.js +0 -0
  168. package/src/{lib/components → components}/Table/_settings.scss +0 -0
  169. package/src/{lib/components → components}/Table/index.js +0 -0
  170. package/src/{lib/components → components}/Tabs/Tabs.jsx +0 -0
  171. package/src/{lib/components → components}/Tabs/Tabs.scss +0 -0
  172. package/src/{lib/components → components}/Tabs/TabsItem.scss +0 -0
  173. package/src/{lib/components → components}/Tabs/_theme.scss +0 -0
  174. package/src/{lib/components → components}/Tabs/index.js +0 -0
  175. package/src/{lib/components → components}/Text/Text.jsx +0 -0
  176. package/src/{lib/components → components}/Text/Text.scss +0 -0
  177. package/src/{lib/components → components}/Text/_helpers/getRootClampClassName.js +0 -0
  178. package/src/{lib/components → components}/Text/_helpers/getRootHyphensClassName.js +0 -0
  179. package/src/{lib/components → components}/Text/_helpers/getRootWordWrappingClassName.js +0 -0
  180. package/src/{lib/components → components}/Text/index.js +0 -0
  181. package/src/{lib/components → components}/TextArea/TextArea.jsx +0 -0
  182. package/src/{lib/components → components}/TextArea/TextArea.scss +0 -0
  183. package/src/{lib/components → components}/TextArea/index.js +0 -0
  184. package/src/{lib/components → components}/TextField/TextField.jsx +0 -0
  185. package/src/{lib/components → components}/TextField/TextField.scss +0 -0
  186. package/src/{lib/components → components}/TextField/index.js +0 -0
  187. package/src/{lib/components → components}/TextLink/TextLink.jsx +1 -1
  188. /package/src/{lib/components → components}/TextLink/TextLink.scss +0 -0
  189. /package/src/{lib/components → components}/TextLink/_theme.scss +0 -0
  190. /package/src/{lib/components → components}/TextLink/index.js +0 -0
  191. /package/src/{lib/components → components}/Toggle/Toggle.jsx +0 -0
  192. /package/src/{lib/components → components}/Toggle/Toggle.scss +0 -0
  193. /package/src/{lib/components → components}/Toggle/index.js +0 -0
  194. /package/src/{lib/components → components}/Toolbar/Toolbar.jsx +0 -0
  195. /package/src/{lib/components → components}/Toolbar/Toolbar.scss +0 -0
  196. /package/src/{lib/components → components}/Toolbar/ToolbarGroup.jsx +0 -0
  197. /package/src/{lib/components → components}/Toolbar/ToolbarItem.jsx +0 -0
  198. /package/src/{lib/components → components}/Toolbar/_helpers/getJustifyClassName.js +0 -0
  199. /package/src/{lib/components → components}/Toolbar/_theme.scss +0 -0
  200. /package/src/{lib/components → components}/Toolbar/index.js +0 -0
  201. /package/src/{lib/components → components}/_helpers/getRootColorClassName.js +0 -0
  202. /package/src/{lib/components → components}/_helpers/getRootSizeClassName.js +0 -0
  203. /package/src/{lib/components → components}/_helpers/getRootValidationStateClassName.js +0 -0
  204. /package/src/{lib/components → components}/_helpers/isChildrenEmpty.js +0 -0
  205. /package/src/{lib/components → components}/_helpers/resolveContextOrProp.js +0 -0
  206. /package/src/{lib/components → components}/_helpers/transferProps.js +0 -0
  207. /package/src/{lib/foundation.scss → foundation.scss} +0 -0
  208. /package/src/{lib/helpers.scss → helpers.scss} +0 -0
  209. /package/src/{lib/provider → provider}/RUIContext.jsx +0 -0
  210. /package/src/{lib/provider → provider}/index.js +0 -0
  211. /package/src/{lib/provider → provider}/withGlobalProps.jsx +0 -0
  212. /package/src/{lib/styles → styles}/_utilities.scss +0 -0
  213. /package/src/{lib/styles → styles}/elements/_code.scss +0 -0
  214. /package/src/{lib/styles → styles}/elements/_links.scss +0 -0
  215. /package/src/{lib/styles → styles}/elements/_lists.scss +0 -0
  216. /package/src/{lib/styles → styles}/elements/_page.scss +0 -0
  217. /package/src/{lib/styles → styles}/elements/_rulers.scss +0 -0
  218. /package/src/{lib/styles → styles}/elements/_small.scss +0 -0
  219. /package/src/{lib/styles → styles}/generic/_box-sizing.scss +0 -0
  220. /package/src/{lib/styles → styles}/generic/_focus.scss +0 -0
  221. /package/src/{lib/styles → styles}/generic/_forms.scss +0 -0
  222. /package/src/{lib/styles → styles}/generic/_reset.scss +0 -0
  223. /package/src/{lib/styles → styles}/generic/_shared.scss +0 -0
  224. /package/src/{lib/styles → styles}/helpers/_animation.scss +0 -0
  225. /package/src/{lib/styles → styles}/settings/_animations.scss +0 -0
  226. /package/src/{lib/styles → styles}/settings/_breakpoints.scss +0 -0
  227. /package/src/{lib/styles → styles}/settings/_escaped-characters.scss +0 -0
  228. /package/src/{lib/styles → styles}/settings/_form-fields.scss +0 -0
  229. /package/src/{lib/styles → styles}/settings/_forms.scss +0 -0
  230. /package/src/{lib/styles → styles}/settings/_utilities.scss +0 -0
  231. /package/src/{lib/styles → styles}/settings/_z-indexes.scss +0 -0
  232. /package/src/{lib/styles → styles}/theme/_accessibility.scss +0 -0
  233. /package/src/{lib/styles → styles}/theme/_borders.scss +0 -0
  234. /package/src/{lib/styles → styles}/theme/_code.scss +0 -0
  235. /package/src/{lib/styles → styles}/theme/_form-fields.scss +0 -0
  236. /package/src/{lib/styles → styles}/theme/_links.scss +0 -0
  237. /package/src/{lib/styles → styles}/theme/_lists.scss +0 -0
  238. /package/src/{lib/styles → styles}/theme/_page.scss +0 -0
  239. /package/src/{lib/styles → styles}/theme/_spacing.scss +0 -0
  240. /package/src/{lib/styles → styles}/theme/_typography.scss +0 -0
  241. /package/src/{lib/styles → styles}/theme-constants/_breakpoints.scss +0 -0
  242. /package/src/{lib/styles → styles}/theme-constants/_colors.scss +0 -0
  243. /package/src/{lib/styles → styles}/theme-constants/_svg.scss +0 -0
  244. /package/src/{lib/styles → styles}/tools/_accessibility.scss +0 -0
  245. /package/src/{lib/styles → styles}/tools/_breakpoint.scss +0 -0
  246. /package/src/{lib/styles → styles}/tools/_colors.scss +0 -0
  247. /package/src/{lib/styles → styles}/tools/_reset.scss +0 -0
  248. /package/src/{lib/styles → styles}/tools/_scrollbar.scss +0 -0
  249. /package/src/{lib/styles → styles}/tools/_spacing.scss +0 -0
  250. /package/src/{lib/styles → styles}/tools/_string.scss +0 -0
  251. /package/src/{lib/styles → styles}/tools/_svg.scss +0 -0
  252. /package/src/{lib/styles → styles}/tools/_transition.scss +0 -0
  253. /package/src/{lib/styles → styles}/tools/_utilities.scss +0 -0
  254. /package/src/{lib/styles → styles}/tools/form-fields/_box-field-layout.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