# How to Manage Dialog Visibility and Communication Between Parent and Child Components in Element UI

> Master Element UI dialogs with parent child component communication. Learn to manage ElDialog visibility using .sync modifiers and emitter methods.

- Repository: [饿了么前端/element](https://github.com/ElemeFE/element)
- Tags: how-to-guide
- Published: 2026-03-07

---

**Element UI's `ElDialog` component implements Vue's `.sync` modifier pattern through a Boolean `visible` prop and `update:visible` events, while mixing in the `emitter` utility to enable `broadcast` and `dispatch` methods for cross-component tree communication.**

Managing modal state across component hierarchies requires predictable data flow and event propagation mechanisms. The **ElemeFE/element** repository solves this through a carefully architected Dialog component that combines Vue's reactive prop system with custom event broadcasting capabilities. Understanding these implementation details allows you to control dialog visibility programmatically and establish communication channels between deeply nested child components and their parents.

## How ElDialog Implements the Vue Sync Pattern

The Dialog component in [`packages/dialog/src/component.vue`](https://github.com/ElemeFE/element/blob/main/packages/dialog/src/component.vue) establishes two-way data binding through prop synchronization rather than direct state mutation.

### The Visible Prop and Watcher Architecture

At the core of visibility management, the component defines a **Boolean `visible` prop** with a default value of `false` (lines 13-16):

```javascript
props: {
  visible: {
    type: Boolean,
    default: false
  }
}

```

A dedicated **watcher** monitors this prop (lines 21-41) and immediately invokes `open()` when the value becomes `true` or `close()` when it becomes `false`. This reactive connection ensures the dialog's display state always reflects the parent's data property without requiring imperative method calls.

### Automatic State Synchronization

When users interact with the dialog—clicking the overlay, pressing Escape, or selecting the close button—the component executes the `hide()` method (lines 76-80). This handler emits `update:visible` with a `false` payload:

```javascript
this.$emit('update:visible', false);

```

Because the parent binds the dialog using `:visible.sync` or `v-model`, Vue automatically updates the parent's data property to match, maintaining a single source of truth across the component boundary.

## Controlling Dialog Visibility from Parent Components

Parents manage dialog state by binding a local data property to the dialog's `visible` prop using Vue's synchronization syntax.

### Using the Sync Modifier

The **`.sync` modifier** provides explicit two-way binding syntax. In your parent component template:

```vue
<template>
  <div>
    <el-button @click="dialogVisible = true">Open Dialog</el-button>
    
    <el-dialog :visible.sync="dialogVisible" title="Settings">
      <p>Dialog content here</p>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false
    };
  }
};
</script>

```

When `dialogVisible` changes to `true`, the watcher in [`component.vue`](https://github.com/ElemeFE/element/blob/main/component.vue) detects the change and triggers the `open()` method. Conversely, when the dialog closes itself, the `update:visible` event updates `dialogVisible` to `false` in the parent.

### Using v-model Directives

Alternatively, you can use **`v-model`** for the same effect, treating the dialog as a form input component:

```vue
<el-dialog v-model="dialogVisible" title="User Preferences">
  <span>Configure your settings below</span>
</el-dialog>

```

Both approaches achieve identical synchronization, though `.sync` explicitly documents the prop name being synchronized.

## Handling Dialog Events in Parent Components

Beyond visibility state, `ElDialog` emits a series of lifecycle events that enable parents to respond to specific modal states.

### Visibility Update Events

The primary communication channel remains the **`update:visible`** event, which fires whenever the dialog's visibility changes. This event integrates seamlessly with the `.sync` modifier but can also be handled manually:

```vue
<el-dialog :visible="dialogVisible" @update:visible="handleVisibilityChange">
  Content
</el-dialog>

```

### Lifecycle Hook Events

According to the source implementation, the component emits four distinct lifecycle events:

- **`open`**: Fired immediately when the dialog begins opening (before animations)
- **`opened`**: Fired after the dialog has fully opened and animations complete
- **`close`**: Fired when the dialog begins closing
- **`closed`**: Fired after the dialog has fully closed

Bind listeners to these events to trigger side effects:

```vue
<el-dialog 
  :visible.sync="dialogVisible"
  @open="fetchData"
  @opened="focusInput"
  @close="confirmUnsavedChanges"
  @closed="resetForm">
  <complex-form-component />
</el-dialog>

```

## Advanced Communication with the Emitter Mixin

For scenarios requiring communication between the dialog and deeply nested children—or between sibling components—the Dialog component leverages the **emitter mixin** from [`src/mixins/emitter.js`](https://github.com/ElemeFE/element/blob/main/src/mixins/emitter.js).

### Broadcast and Dispatch Methods

The emitter mixin provides two critical methods for component tree traversal:

- **`dispatch(componentName, eventName, params)`**: Travels upward through parent components until it finds a component matching `componentName`, then emits the event on that component.
- **`broadcast(componentName, eventName, params)`**: Travels downward through child components, finding all instances matching `componentName` and emitting the event on each.

These methods are mixed into `ElDialog` alongside `Popup` and `Migrating` mixins (as seen in [`component.vue`](https://github.com/ElemeFE/element/blob/main/component.vue)), giving the dialog event propagation capabilities beyond standard Vue `$emit`.

### Practical Cross-Component Implementation

When a grandchild component nested inside the dialog needs to signal the dialog directly:

```vue
<!-- GrandchildComponent.vue -->
<template>
  <el-button @click="notifyDialog">Submit</el-button>
</template>

<script>
export default {
  methods: {
    notifyDialog() {
      // Dispatch upward to find the ElDialog parent
      this.dispatch('ElDialog', 'custom-submit', { data: 'payload' });
    }
  }
};
</script>

```

The parent dialog listens for this custom event:

```vue
<el-dialog :visible.sync="visible" @custom-submit="handleSubmission">
  <grandchild-component />
</el-dialog>

```

Similarly, a parent component can broadcast downward to all child inputs within a dialog form:

```javascript
// In parent method
this.broadcast('ElInput', 'clear-validation', []);

```

## Key Source Files and Architecture

Understanding the complete implementation requires examining these specific files in the ElemeFE/element repository:

- **[`packages/dialog/src/component.vue`](https://github.com/ElemeFE/element/blob/main/packages/dialog/src/component.vue)**: Core component logic including the `visible` prop definition, watcher implementation (lines 21-41), and `hide()` method (lines 76-80) that emits closure events.
- **[`src/utils/popup/index.js`](https://github.com/ElemeFE/element/blob/main/src/utils/popup/index.js)**: The **Popup mixin** providing modal overlay management, z-index coordination, and body scroll locking functionality mixed into the Dialog component.
- **[`src/mixins/emitter.js`](https://github.com/ElemeFE/element/blob/main/src/mixins/emitter.js)**: Defines `broadcast` and `dispatch` methods used for cross-component communication when standard prop drilling becomes impractical.
- **[`packages/dialog/index.js`](https://github.com/ElemeFE/element/blob/main/packages/dialog/index.js)**: Public API entry point that registers the component globally.

## Summary

- **`ElDialog` uses a Boolean `visible` prop** (default `false`) defined in [`packages/dialog/src/component.vue`](https://github.com/ElemeFE/element/blob/main/packages/dialog/src/component.vue) to control display state reactively.
- **A prop watcher** (lines 21-41) monitors `visible` changes and triggers `open()` or `close()` methods automatically.
- **The `.sync` modifier or `v-model`** enables parents to bind data properties while the dialog emits `update:visible` events to maintain synchronization.
- **Lifecycle events** (`open`, `opened`, `close`, `closed`) provide hooks for executing logic at specific modal transition points.
- **The `emitter` mixin** from [`src/mixins/emitter.js`](https://github.com/ElemeFE/element/blob/main/src/mixins/emitter.js) adds `broadcast` and `dispatch` methods for propagating events up or down the component tree, facilitating communication between nested children and the dialog or parent components.

## Frequently Asked Questions

### How does the visible prop work in Element UI Dialog?

The `visible` prop is defined as a Boolean with a default value of `false` in [`packages/dialog/src/component.vue`](https://github.com/ElemeFE/element/blob/main/packages/dialog/src/component.vue) (lines 13-16). A Vue watcher monitors this prop (lines 21-41); when the parent changes the bound value to `true`, the watcher invokes `open()` to display the dialog. When the dialog closes via user interaction, it emits `update:visible` with `false`, automatically updating the parent's data property when using `.sync` or `v-model`.

### What is the difference between using v-model and the sync modifier for dialog visibility?

Both approaches achieve identical two-way data binding. The **`.sync` modifier** explicitly binds the `visible` prop using `:visible.sync="property"` syntax, while **`v-model`** provides a more concise directive that internally manages the prop and event binding. The `.sync` modifier makes the synchronized prop name explicit in your template, whereas `v-model` assumes the primary value prop. Both rely on the `update:visible` event emitted from the `hide()` method (lines 76-80).

### How can child components inside a dialog communicate with the parent component?

Child components have three communication pathways: standard **`$emit`** events bubble up through the template hierarchy and can be captured by the parent listening on the dialog slot content; the **`dispatch`** method (from the emitter mixin) walks up the component tree to find the dialog or parent by `componentName` and emit events directly; and **`broadcast`** allows ancestors to send events downward to specific child component types. The emitter mixin in [`src/mixins/emitter.js`](https://github.com/ElemeFE/element/blob/main/src/mixins/emitter.js) provides these tree-traversal utilities.

### What events does ElDialog emit during its lifecycle?

`ElDialog` emits **`update:visible`** whenever the visibility state changes, enabling two-way binding. Additionally, it emits four lifecycle events: **`open`** when opening begins, **`opened`** after opening animations complete, **`close`** when closing begins, and **`closed`** after closing animations finish. These events allow parent components to synchronize data fetching, focus management, or form reset logic with the dialog's visual state transitions.