> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://contentful.com/developers/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://contentful.com/developers/docs/_mcp/server.

# Target State

> Target State is the understanding of where your app is rendered. It is responsible specific fields, sidebars and editors in the web app.

The `targetState` data structure defines where an app will render. It is responsible for assigning an app to specific fields, sidebars, and editors in the web app during the configuration of an app as well as setting any [instance parameters](/extensibility/app-framework/app-parameters#instance-parameters) required by the app. We use the term `targetState` because it refers to the state of an environment after the app is configured.

## Understanding the `targetState` object

To get a better understanding of when and how `targetState` is used, we will go through an example. The following code shows a component that is used for the app.

```js
class Config extends Component {
  // We are skipping the render example because it is not relevant to this example.
  render() { ... }
  // This method will be called when a user clicks on "Install"
  // or "Save" in the configuration screen.
  //
  // We want to do two things in here:
  // 1. Persist selected values as a parameter
  // 2. Assign the app to sidebars of all Content Types
  async onConfigure() {
    // Get current state
    // This will be used as base for next state updates
    const currentState = await sdk.app.getCurrentState();
    // The return value of `onConfigure` is used to install
    // or update the configuration.
    return {
      // Parameters to be persisted as the app's installation parameters.
      parameters: { ... },
      // Transformation of an environment performed in the
      // installation process.
      targetState: {
        EditorInterface: {
          // Always pass in the `currentState` to avoid
          // removing any previous location configuration
          ...currentState?.EditorInterface,
          // A content type id where we will assign the app to the sidebar
          'my-content-type-id': {
              // assignment to sidebar in position 0 (will show up at the very top of the sidebar)
              sidebar: { position: 0 }
          }
        }
      },
    };
  }
}
```

The `targetState` is part of the object that you can optionally return in your `onConfigure` function. The keys of the [`EditorInterface`](/extensibility/app-framework/editor-interfaces) are the IDs of content types we want to configure for the app. In the code example above, `my-content-type-id` is the ID of a content type that will have our example app in the sidebar at position 0, which means it will be the first thing you see. Apps can leverage different [`locations`](/extensibility/app-framework/locations) to cover different use cases. It is especially important to note here that we always include the `currentState` to preserve the current `EditorInterface` state upon configuration updates.
In the example above we were only interested in installing the app in the sidebar location. Below, we will illustrate how to install an app into different locations.

> **Info**
>
> **Omitting the `targetState` key in the object returned by `onConfigure` will remove any previous app location assignment and instance parameters!**

### Usage

An example of how to use `targetState` to assign an app to selected Content Types
can be found [here](https://github.com/contentful/apps/tree/master/examples/content-type-selection-config).

### Entry editor location

If you want an app to be rendered as a new [entry editor](/extensibility/app-framework/locations#entry-editor), you need to specify the key `editors` property for the desired content type. The expected value is an object whose `position` represents the location (zero-based) of the editor in the list of editors.
The editors object can also contain an optional key `settings` which can be used to set any [instance parameters](/extensibility/app-framework/app-parameters#instance-parameters) used by the app.

```js
async onConfigure() {
  // Get current state
  // This will be used as base for next state updates.
  const currentState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration.
        ...currentState?.EditorInterface,
        'my-content-type-id': {
            editors: {
              // Places the entry at the second position
              // (position = 1) in the editors list for the
              // content type with ID `my-content-type-id`.
              position: 1,

              // Set values for this location for the app's instance parameters
              settings: {
                parameterOne: true,
                anotherParamter: 'orange'
              }
            }
        }
      }
    },
  };
}
```

### Field location

If you want an app to render as an [entry field](/extensibility/app-framework/locations#entry-field), specify the `controls` property with the field IDs of the content type you want to replace with your app.
Each control object can also contain an optional key `settings` which can be used to set any [instance parameters](/extensibility/app-framework/app-parameters#instance-parameters) used by the app.

```js
async onConfigure() {
  // Get current state
  // This will be used as base for next state updates
  const currentState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration
        ...currentState?.EditorInterface,
        // Render the app as two field editors of the content
        // type with ID `another-content-type` (field: `my-field-id`)
        'my-content-type-id': {
            controls: [
            { fieldId: 'my-field-id' },
            { fieldId: 'a-field-with-instance-parameters', settings: { parameter: true } },
          ]
        }
      }
    },
  };
```

### Entry sidebar location

If you want an app to render in the [sidebar](/extensibility/app-framework/locations#entry-sidebar) of your entry editor, you need to specify the `sidebar` property as the key for your desired content type. The `position` value refers to the order in which the app is rendered in the sidebar. `0` means that the app is rendered at the first position.
The sidebar object can also contain an optional key `settings` which can be used to set any [instance parameters](/extensibility/app-framework/app-parameters#instance-parameters) used by the app.

```js
async onConfigure() {
  // Get current state
  // This will be used as base for next state updates
  const currentState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration
        ...currentState?.EditorInterface,
        'my-content-type-id': {
          sidebar: {
            // Render the app on the top (position = 0) of the
            // sidebar for the content type with ID `my-content-type-id`.
            position: 0,

            // Optionally set instance parameters used by the app
            settings: {
              parameterOne: true,
              anotherParamter: 'orange'
            }
          }
        }
      }
    },
  };
}
```

### Entry dialog location

[Dialog locations](/extensibility/app-framework/locations#dialog) are enabled by default and do not require any extra properties in the `targetState`.

### Page location

Since the [page location](/extensibility/app-framework/locations#page) is its own route in the web app and does not interfere with the [`EditorInterface`](/extensibility/app-framework/editor-interfaces) at all, there is no extra property needed for the `targetState`.

### Multiple content types and locations

Since the `targetState` is a plain JavaScript object, we can add multiple keys to the `EditorInterface` property. This allows us to support multiple content types and location configurations to build more complex apps. The following example defines a `targetState` using three content types.

```js
async onConfigure() {
   // Get current state
  // This will be used as base for next state updates
  const appState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration
        ...currentState?.EditorInterface,
        // Places the entry at the second position in the editors
        // list for the content type with ID `my-content-type-id`
        'my-content-type-id': {
            editors: { position: 1 }
        },
        // Places the entry at the first position in the editors
        // list for the content type `another-content-type-id`
        'another-content-type-id': {
            editors: { position: 0 }
        },
        // Render the app as two field editors
        // and render the app on the top (position = 0) of the
        // sidebar for the content type with ID `another-content-type`
        'another-content-type': {
          sidebar: { position: 0 },
          controls: [
            { fieldId: 'title' },
            { fieldId: 'metadata' }
          ]
        }
      }
    },
  };
}
```