With React, declarative programming has become the dominant paradigm for building user interfaces. However, there are
instances where imperative programming can offer unique advantages, particularly when it comes to dialog-based user interactions. In this blog post, we will explore the concept of imperative dialog UI (in React), discussing its pros and cons and how you can benefit from this.

Dialogs play a crucial role in user interfaces by facilitating communication, interaction, and information exchange between the user and the application. They are UI components that display content or request input in a separate window or overlay, often appearing as pop-ups. Dialogs serve several important purposes:
- Content Presentation: Dialogs are used to present information to the user in a focused and attention-grabbing manner. They can display messages, alerts, notifications, warnings, or other important content that requires immediate attention or acknowledgment.
- User Input and Feedback: Dialogs provide a means for users to input data or make selections. They can prompt users for specific information, such as filling out forms, confirming actions, or providing options through radio buttons, checkboxes, or dropdown menus. Dialogs also provide feedback by displaying validation errors or success messages based on user input.
- Workflow and Decision Flow: Dialogs help guide users through workflows and decision-making processes. They can present a series of steps or questions, enabling users to make choices or perform actions in a structured manner. Dialogs facilitate the logical flow of tasks, ensuring that users are aware of the context and consequences of their actions.
- Modal Interactions: Dialogs often appear as modal windows, which means they require users to interact with them before returning to the main interface. This helps draw attention to the dialog's content and ensures that users address the information or input request before proceeding. Modal dialogs prevent users from interacting with other parts of the application until the dialog is closed or completed.
- Error Handling: Dialogs can be used to inform users about errors or exceptional situations that occur during their interaction with the application. Error dialogs provide relevant information, guidance, and potential solutions to help users understand and resolve issues.
- Confirmation and Alerts: Dialogs are commonly employed to seek confirmation from users before performing critical actions that could have significant consequences. For example, they may ask for confirmation before deleting data, submitting a form, or initiating irreversible actions. Alerts can also be displayed using dialogs to notify users of important updates, system status, or time-sensitive information.
# Declarative UI
Dialogs in UI libraries are typically designed with a declarative approach, lacking imperative alternative APIs. This inclination towards declarative dialogs can be attributed to their prevalence in complex and enduring scenarios, which remain the most common use case.
Here's an example of a Dialog using MUI (adapted example from MUI docs)
const Item = ({ title, id }) => { const [open, setOpen] = React.useState(false);
const handleOpen = () => { setOpen(true); };
const handleClose = () => { setOpen(false); }; const handleConfirm = () => { deleteItem(id); setOpen(false); }; const handleCancel = () => { setOpen(false); };
return ( <React.Fragment> <Card> <CardTitle>{title}</CardTitle> <CardActions> <Button onClick={handleOpen}>Delete</Button> </CardActions> </Card>
<Dialog open={open} onClose={handleClose}> <DialogTitle> Are you sure? </DialogTitle> <DialogContent> <DialogContentText> This action is irreversible </DialogContentText> </DialogContent> <DialogActions> <Button onClick={handleCancel}>Cancel</Button> <Button onClick={handleConfirm} autoFocus> Continue </Button> </DialogActions> </Dialog> </React.Fragment> );}
While declarative is a flexible approach, it is important to acknowledge that it may become excessive for situations where user confirmation or input is required. Rendering the dialog, controlling the visibility state, and the output data for every dialog action can become a spaghetti code.
See how an imperative dialog works in this scenario:
const Item = ({ id, title }) => { const confirm = useConfirm();
const handleDelete = () => { confirm({ title: "Are you sure?", text: "This action is irreversible", onConfirm: () => deleteItem(id), // onCancel: () => {/* do nothing */}, }); }
return ( <Card> <CardTitle>{title}</CardTitle> <CardActions> <Button onClick={handleDelete}>Delete</Button> </CardActions> </Card> );};