---
title: "lzb.components.PreviewServerCallback.onChange"
description: "JS action `lzb.components.PreviewServerCallback.onChange` of the Lazy Blocks WordPress plugin."
url: "https://www.lazyblocks.com/docs/js-actions/lzb-components-previewservercallback-onchange/"
lastUpdated: 2026-09-09
source: "js-actions/lzb-components-previewservercallback-onchange.mdx"
---
# lzb.components.PreviewServerCallback.onChange

Fires in the editor after a block preview has been rendered with a new response. It is where a script starts up again on the fresh markup, the counterpart to the teardown in [lzb.components.PreviewServerCallback.onBeforeChange](https://www.lazyblocks.com/docs/js-actions/lzb-components-previewservercallback-onbeforechange/).

It runs from an effect that skips the first render and then fires for every response, the first one included. A failed request counts as a response, and so does a block with no render callback, which renders as nothing, so the markup a handler is looking for is not guaranteed to be on the page.

The same effect lists the component's props among its dependencies, and the block that owns the preview hands it a fresh props object on every one of its renders. The action therefore fires again on renders where no new response arrived. A handler has to be safe to run repeatedly.

## Attributes

| Name    | Type       | Description                    |
| ------- | ---------- | ------------------------------ |
| `props` | **Object** | props of the preview component |

| Name             | Type               | Description                                                                     |
| ---------------- | ------------------ | ------------------------------------------------------------------------------- |
| `block`          | **String**         | block name, for example `lazyblock/slider`                                      |
| `attributes`     | **Object \| null** | attributes sent for rendering, `null` when the caller passed none               |
| `urlQueryArgs`   | **Object**         | extra fields merged into the REST request body, `{}` by default                 |
| `onBeforeChange` | **Function**       | the component's own callback for the teardown that came before                  |
| `onChange`       | **Function**       | the component's own callback, called immediately before this action             |
| `withBlockProps` | **Boolean**        | whether the rendered markup is wrapped with the block props, `false` by default |
| `context`        | **Object**         | block context sent to the server                                                |
| `clientId`       | **String**         | client id of the block, passed in by the caller and forwarded untouched         |

## Usage

```js title="JS"
wp.hooks.addAction(
  "lzb.components.PreviewServerCallback.onChange",
  "my.custom.namespace",
  function (props) {
    if (props.block !== "lazyblock/slider") {
      return;
    }

    const node = document.querySelector(
      `[data-block="${props.clientId}"] .my-slider`,
    );

    if (node && !node.mySlider) {
      node.mySlider = new window.MySlider(node);
    }
  },
);
```

## Deprecated alias

`lazyblocks.components.PreviewServerCallback.onChange` fires immediately after this one, with the same single argument. It is kept so old integrations keep working. Do not add handlers to it in new code.

Guard on `props.block` and check the node before touching it, as the example does. The action fires for every previewed block on the page, not only the one being edited, and the `!node.mySlider` test is what keeps a repeat run from building a second instance on the same node.

## Documentation Index
> Fetch the complete documentation index at: https://www.lazyblocks.com/llms.txt
> Fetch every page in a single file at: https://www.lazyblocks.com/llms-full.txt
