# How Dioxus Renderers Apply DOM Changes Using WriteMutations

> Learn how Dioxus renderers apply DOM changes using WriteMutations. Discover how abstract mutation instructions are translated into platform-specific UI updates for the Dioxus renderer.

- Repository: [Dioxus Labs/dioxus](https://github.com/DioxusLabs/dioxus)
- Tags: internals
- Published: 2026-07-23

---

**Dioxus renderers apply DOM changes by implementing the `WriteMutations` trait, which translates abstract mutation instructions from the VirtualDom diffing algorithm into platform-specific UI updates.**

The Dioxus framework separates Virtual DOM reconciliation from actual UI updates through a well-defined abstraction layer. When the `VirtualDom` calculates differences between renders, it outputs a sequence of `Mutation` objects rather than touching the DOM directly. Each platform renderer implements the **`WriteMutations`** trait to convert these mutations into concrete API calls, whether targeting browser DOM, native widgets, or serialized network messages.

## The WriteMutations Trait Interface

The core contract lives in [`packages/core/src/mutations.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/core/src/mutations.rs). This trait defines the primitive operations that any renderer must support to synchronize the Virtual DOM with a real UI tree.

### Core Mutation Methods

The trait specifies methods that map directly to fundamental DOM operations:

- `append_children(id, m)` – Attaches `m` nodes from the internal stack to the element identified by `ElementId`.
- `assign_node_id(path, id)` – Binds a generated `ElementId` to a placeholder at a specific child path.
- `create_placeholder(id)` – Inserts a temporary placeholder node, primarily used during list diffing.
- `create_text_node(value, id)` – Generates a new text node containing the specified string.
- `load_template(template, index, id)` – Clones a node from a pre-registered template cache.
- `replace_node_with(id, m)` – Swaps the existing node with `m` nodes popped from the stack.
- `insert_nodes_before(id, m)` and `insert_nodes_after(id, m)` – Insert nodes relative to an existing element.
- `set_attribute(name, ns, value, id)` – Updates an attribute, optionally within a namespace.
- `set_node_text(value, id)` – Modifies the text content of an existing text node.
- `create_event_listener(name, id)` and `remove_event_listener(name, id)` – Manage event handler attachments.
- `remove_node(id)` – Deletes a node from the UI tree.
- `push_root(id)` – Pushes the root node onto the mutation stack when beginning a new subtree.

## Web Renderer Implementation

The Web renderer implements `WriteMutations` for the `WebsysDom` struct in [`packages/web/src/mutations.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/web/src/mutations.rs). This implementation bridges the abstract mutations to `web_sys` browser APIs.

```rust
impl WriteMutations for WebsysDom {
    fn append_children(&mut self, id: ElementId, m: usize) {
        // Resolve the element from its id, then call `append_child` on the
        // underlying `web_sys::Node` for each of the `m` stacked nodes.
    }
    
    fn set_attribute(&mut self, name: &'static str, ns: Option<&'static str>,
                     value: &AttributeValue, id: ElementId) {
        // Convert `AttributeValue` to a string and call `set_attribute`
        // (or `set_attribute_ns` when a namespace is supplied) on the
        // `web_sys::Element`.
    }
    
    // Additional methods map similarly to `web_sys` calls
}

```

During `VirtualDom::render_immediate` or `VirtualDom::rebuild`, the diffing engine invokes these methods, causing immediate updates to the browser's document tree.

## Native DOM Renderer Implementation

For desktop and native applications, the `MutationWriter` struct in [`packages/native-dom/src/mutation_writer.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/native-dom/src/mutation_writer.rs) provides the `WriteMutations` implementation. This writer maintains a mapping from `ElementId` to native widget handles.

```rust
impl WriteMutations for MutationWriter<'_> {
    fn create_text_node(&mut self, value: &str, id: ElementId) {
        // Create a native text node via the underlying renderer and store it
        // in the writer's internal map keyed by `id`.
    }
    
    fn replace_node_with(&mut self, id: ElementId, m: usize) {
        // Remove the existing native widget and insert the stacked `m` widgets.
    }
    
    // Other methods map to the native widget-tree API
}

```

This abstraction allows the native renderer to use platform-specific widget toolkits while presenting a uniform interface to the core diffing algorithm.

## Server-Side and LiveView Implementation

The server-side "interpreter" used by LiveView implements `WriteMutations` in [`packages/interpreter/src/write_native_mutations.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/interpreter/src/write_native_mutations.rs). Rather than applying changes immediately, this implementation serializes mutations into a transmittable format that can be sent over a network connection and replayed on the client.

## How the Mutation Pipeline Works

The separation of concerns follows a strict three-phase architecture:

1. **Diffing Phase**: The `VirtualDom` in [`packages/core/src/virtual_dom.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/core/src/virtual_dom.rs) compares the previous and current component trees, generating a sequence of `Mutation` objects.
2. **Translation Phase**: The renderer's `WriteMutations` implementation receives each mutation and converts it into platform-specific calls.
3. **Application Phase**: The underlying platform API (Web DOM, native widgets, or network buffer) applies the changes to the visible UI.

This design ensures that component logic, hooks, and lifecycle management remain platform-agnostic while allowing each renderer to optimize its specific update strategy.

## Practical Usage Examples

### Collecting Mutations Without a Real DOM

You can inspect the mutation stream without applying it to an actual UI:

```rust
use dioxus_core::{VirtualDom, Mutations, WriteMutations};

fn main() {
    // Build a VirtualDom from a component
    let mut vdom = VirtualDom::new(|cx| {
        cx.render(rsx! {
            div { "Hello, Dioxus!" }
        })
    });

    // Collect mutations without touching a real DOM
    let mut collector = Mutations::default();
    vdom.rebuild(&mut collector);

    // `collector.edits` now holds the exact DOM operations needed
    println!("{:#?}", collector.edits);
}

```

### Rendering to the Web Platform

To apply mutations to a browser document:

```rust
use dioxus_web::WebsysDom;
use dioxus_core::VirtualDom;

let mut vdom = VirtualDom::new(app);
let mut web_dom = WebsysDom::new(); // wraps the browser's document
vdom.rebuild(&mut web_dom); // real DOM is updated in the browser

```

## Summary

- The **`WriteMutations`** trait defines the contract between Dioxus core and platform renderers.
- **Web renderers** implement the trait using `web_sys` APIs in [`packages/web/src/mutations.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/web/src/mutations.rs).
- **Native renderers** use `MutationWriter` in [`packages/native-dom/src/mutation_writer.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/native-dom/src/mutation_writer.rs) to map mutations to widget handles.
- The **interpreter** serializes mutations for server-side rendering in [`packages/interpreter/src/write_native_mutations.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/interpreter/src/write_native_mutations.rs).
- This architecture decouples diffing logic from DOM manipulation, enabling Dioxus to target multiple platforms with a single component model.

## Frequently Asked Questions

### What is the difference between Mutations and WriteMutations in Dioxus?

`Mutations` is a concrete type that collects mutation instructions into a vector for inspection or serialization. `WriteMutations` is the trait that defines how those instructions are applied to a real UI. Renderers implement `WriteMutations` to specify how each operation translates to platform-specific code.

### Can I implement WriteMutations for a custom target platform?

Yes. Any platform that can represent nodes with unique identifiers and supports basic CRUD operations on a tree structure can implement `WriteMutations`. You must handle the fifteen primitive methods defined in [`packages/core/src/mutations.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/core/src/mutations.rs), mapping them to your platform's native API.

### How does Dioxus handle attribute namespaces in WriteMutations?

The `set_attribute` method accepts an optional `ns` parameter of type `Option<&'static str>`. When present, the Web renderer calls `set_attribute_ns` on the DOM element; native renderers can use the namespace to determine appropriate property setting behavior on their underlying widgets.

### Where does the VirtualDom call WriteMutations methods?

The `VirtualDom` invokes `WriteMutations` methods during `rebuild()` and `render_immediate()` cycles defined in [`packages/core/src/virtual_dom.rs`](https://github.com/DioxusLabs/dioxus/blob/main/packages/core/src/virtual_dom.rs). These methods traverse the component tree and emit mutations whenever they detect differences between the current and previous renders.