Affirmitive to affirmative.
4.5 KiB
Dialog
Dialogs are the high-level component used to render popups such as Preferences,
and repository setting as well as error messages. They're built upon the new
dialog
html element and are shown as modals which means that tab navigation
are constrained to within the dialog itself.
General structure
<Dialog title='Title'>
<TabBar>...</TabBar>
<DialogContent>
...
</DialogContent>
<DialogFooter>
<OkCancelButtonGroup />
</DialogFooter>
</Dialog>
Footer
A typical dialog footer will normally be made up of two buttons, an affirmative/Ok
button and a dismissal/Cancel button. The ordering of these two buttons is
platform-specific, see our dedicated documentation about button order
for the specifics. For this reason we have a dedicated component called
OkCancelButtonGroup
which is used in the majority of our dialogs and renders
the buttons in the expected order for the platform.
For dialogs that only need a single button it's possible to use the OkCancelButtonGroup
but for simple dialogs it's probably better to replace the DialogFooter
component
with the DefaultDialogFooter
component which includes a single close button.
OkCancelButtonGroup
The OkCancelButtonGroup
is a high-level component which aims to eliminate the decision
making process around which order buttons should appear on the different platforms.
Used without any props the component will render two buttons, Ok
, and Cancel
. By
default the Ok
button will trigger the onSubmit
event on the Dialog
and the Cancel
button will trigger the onDismissed
event. It's possible to add a button-specific
event handler instead of relying on the dialog submit/dismiss events but it's rarely
necessary.
The destructive
prop controls whether a dialog is considered destructive. One
definition of a destructive dialog is if the user chooses to answer the dialog in
the affirmative (Ok
) whether the subsequent action be dangerous and/or hard to
recover from. Setting the destructive
prop will make the dismissal (Cancel
)
button the default button (i.e. it will be the submit button). Note that setting
the destructive
prop does not impact which button triggers the onSubmit
vs
onDismissed
event on the dialog so converting a previously non-destructive dialog
to a destructive one is as simple as setting the prop on the button group.
Errors
Dialogs should, when practical, render errors caused by its actions inline as
opposed to opening an error dialog. An example of this is the Preferences dialog.
If the dialog fails to write to the .gitignore
or git config files as part of
persisting changes it renders a short error message inline in the dialog using
the DialogError
component.
The DialogError
component, if used, must be the first child element of the
Dialog itself.
<Dialog title='Preferences'>
<DialogError>Could not save ignore file. EPERM Something something</DialogError>
<TabBar>...</TabBar>
<DialogContent>
...
</DialogContent>
<DialogFooter>
<OkCancelButtonGroup />
</DialogFooter>
</Dialog>
The content inside of the DialogError
should be primarily text based. Avoid using
the term 'Error' inside the text as that should be evident already based on the
styling of the DialogError
component.
Best practices
DO: Let children render the DialogContent
component
If you're using a one-child-per-tab approach you should render the DialogContent
as the top-level element in those children instead of wrapping children inside the
DialogContent
element. This avoid needless nesting and lets us leverage generic
dialog/form/row styles in a more straightforward way.
Example (good)
// SomeComponent.tsx
<Dialog title='Title'>
<TabBar>...</TabBar>
{this.renderActiveTab()}
<DialogFooter>
<OkCancelButtonGroup />
</DialogFooter>
</Dialog>
// ChildComponent.tsx
<DialogContent>
my fancy content
</DialogContent>
Example (bad)
// SomeComponent.tsx
<Dialog title='Title'>
<TabBar>...</TabBar>
<DialogContent>
{this.renderActiveTab()}
</DialogContent>
<DialogFooter>
<OkCancelButtonGroup />
</DialogFooter>
</Dialog>
// ChildComponent.tsx
<div>
my fancy content
</div>
DO: Use Row components to lay out content
The Row
component receives a bottom margin, when used as an immediate
child of DialogContent
, making it an excellent tool for structuring content.
If the content is primary text, as opposed to form component the <p>
element
should be used instead of the Row
component.