---
title: 'Administration Components: State and Data Flow | Shopware Community Hub'
description: >-
  Learn how to use the Vue 3 Options API to manage state inside Shopware
  administration components.
canonical_url: >-
  https://hub.shopware.com/learn/unit/administration-components-state-and-data-flow
---

# Administration Components: State and Data Flow

<LearningObjectives>

- Know that administration components use the Vue 3 **Options API** with many available options.
- Learn the fundamental **state-related options** (props, data, computed, methods, watch, emits).
- Understand **how these state options are used** and when to apply them.

</LearningObjectives>

# Administration Components: State and Data Flow

Before we continue, let's start with a short self-check about components and a quick recap:

<ArticleMultipleQuestionnaire>
  <ArticleQuestionnaire>
    <ArticleQuestionnaireQuestion>What is correct about components in the Shopware Administration?</ArticleQuestionnaireQuestion>
    <ArticleQuestionnaireAnswer correct>Vue-based UI building blocks</ArticleQuestionnaireAnswer>
    <ArticleQuestionnaireAnswer>It's backend service that handle business logic in PHP</ArticleQuestionnaireAnswer>
    <ArticleQuestionnaireAnswer correct>Can be reused inside pages</ArticleQuestionnaireAnswer>
    <ArticleQuestionnaireAnswer>Templates that are rendered directly without a module</ArticleQuestionnaireAnswer>
  </ArticleQuestionnaire>
</ArticleMultipleQuestionnaire>

In the previous course, you already worked with components in two different contexts:

- You learned **where** components live in your plugin and how they fit into the modules-page-component hierarchy.
- You learned **how** components are registered and extended using `Shopware.Component.register` and `Shopware.Component.extend`

At this point, you should already know that:

- Components are Vue-based UI building blocks.
- Pages are components that act as route targets.
- Modules do **not** render UI, but map routes to components.
- Templates using Twig.js, not Vue Single File Components (SFCs).
- Components are **globally discoverable** through the Shopware component registry.

You know the basics, but you still need to know more about them – the **Options API**. In this learning unit, you will learn about the `State` of the Options API.

## Options API

Shopware administration components are Vue components built with the **Vue 3 Options API**.

This means you work with familiar options such as `data`, `computed`, `methods`, and `lifecycle hooks`, while the component itself is integrated into the Shopware administration (e.g., `Shopware.Component.register`).

Below is an overview of the most important options.

## Options API: Rendering

### Template

As you already know, the `template` defines the rendered HTML structure of a component (`.html.twig` file).

## Options API: State

### Props

Props allow a parent component to pass data to a child component.

Each prop can define `type`, `required`, and `default`. For example:

```js
export default {
  props: {
    color: {
      type: String,
      default: 'red'
    },
    size: {
      type: String,
      default: null
    }
  }
}
```

The common available types include: String, Number, Boolean, Object, Array, Function. For more information, which other types Vue supports, check the [documentation](https://vuejs.org/guide/components/props.html#runtime-type-checks).

Props follow Vue's **one-way data flow**: Updating the prop in the parent updates the child – but not the other way around. A child component should **never mutate a prop directly**, as Vue will warn about this.

If a child component needs an editable version of a prop, you can initialize a local copy in the `data` option.

### Data

The `data()` option defines a component's **local reactive state**. Unlike props, data belongs only to the component itself. You can think of it as the component's instance, like the instance variables in PHP.

**Example:**

Your parent provides these props:

```js
export default {

  props: {
    color: {
      type: String,
      default: 'red'
    },
    size: {
      type: String,
      default: null
    }
  }
}
```

The child component may want its own editable local version of a value:

```js
export default {
  props: {
    height: {
      type: Number,
      default: 0
    },
    width: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      color: 'blue' // Creates a local copy of the prop
    }
  }
}
```

In the `data` option, it creates a copy of the prop `color` from the parent component and overrides it with a new value. This pattern is especially useful for:

- Text inputs
- Toggles
- Form fields that need internal buffering
- Value that the user edits before saving

It allows a component to maintain its own internal state while still receiving initial value from the parent.

### Computed

The `computed` option is used to define derived values based on reactive state (`props` or `data`). A computed property is automatically **cached** and only re-evaluated when its dependencies change.

Computed properties are ideal for:

- Transforming or formatting data
- Combining multiple `props` or `data` values
- Performing lightweight calculations
- Keeping templates clean and readable

**Example: Basic (read-only) computed property**

```js
export default {
  props:{
    firstName: String,
    lastName: String
  },
  
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    }
  }
}
```

The function `fullName()` is called whenever the `firstName` or `lastName` prop changes. It returns a new value based on the current state of the component. Vue caches the result until one of the dependencies changes. This is the most common usage of computed properties.

**Example: Writable computed (with getter and setter):**

Computed properties can also be writable by defining both `get` and `set`. This is useful when the computed value should also update the underlying state:

```js
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },

  computed: {
    fullName: {
      get() {
        return `${this.firstName} ${this.lastName}`;
      },
      set(value) {
        const [ first, last ] = value.split(' ');
        this.firstName = first;
        this.lastName = last ?? '';
      }
    }
  }
}
```

Now here is how a writable computed property works with `v-model`:

```twig
<input type="text" v-model="fullName">
```

When the user types `Max Mustermann` in the input field, Vue executes:

```js
this.fullName = "Max Mustermann";
```

And the computed setter splits it:

```js
this.firstName = "Max";
this.lastName = "Mustermann";
```

**More examples:**

Most computed properties are **read-only** and used to transform or format values for display.

```js
export default {
  computed: {
    formattedPrice() {
      return this.price.toFixed(2) + ' €';
    },
    isDisabled() {
      return !this.product || this.product.isLoading;
    },
    activeUsers() {
      return this.users.filter(user => user.isActive);
    },
    displayName() {
      return `${this.user.firstName} (${this.user.email})`;
    }
  }
}
```

These examples show how computed properties help maintain clean templates and centralize UI logic.

<Callout title="Difference between data and computed" type="info">

`data` defines the **raw, local state** of a component – values that the component owns and can modify. Use it for anything the user can edit or that changes over time.

`computed` defines **derived values** based on existing state (from `props` or `data`). It does **not** store its own data, but calculates a result from `props`, `data`, or other computed values. Vue automatically caches the result and re-evaluates it only when its dependencies change. Use it for values that depend on another state and should update automatically.

</Callout>

### Methods

The `methods` option defines **functions** (as you know from other programming languages) that belong to the component.

Methods are used to perform actions. They run whenever they are called and are ideal for handling events, user interactions, API calls, or updating the component's state.

**For example:**

```js
export default {
  data(){
    return {
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
    },
    decrement() {
      this.count--;
    },
    reset() {
      this.count = 0;
    }
  }
}
```

And in the template:

```twig
<button @click="increment">Increase</button>
<button @click="decrement">Decrease</button>
<button @click="reset">Reset</button>

<p>Current count: {{ count }}</p>
```

When the user clicks a button, Vue calls the corresponding method and updates the component's state immediately.

As you can see, you can use methods and call it from the template to implement the desired behavior.

<Callout title="Methods vs. Computed" type="info">

Use methods **to do** things.

Use computed **to show** things.

</Callout>

### Watch

The `watch` option allows you to **react to changes** in reactive values such as `props`, `data`, or `computed` properties.

While computed properties are used to **derive values** for the template, **watchers** are used to perform **side effects** when something changes.

Common use cases for watchers include:

- Reloading data from a repository when a filter changes
- Validating input fields
- Triggering debounced operations
- Responding to nested object changes (e.g., search criteria)

A watcher runs its **callback functions** whenever the watched value changes.

**Basic example: Watching a simple value:**

```js
export default {
  data() {
    return {
      searchTerm: '',
      products: []
    };
  },
  watch: {
    searchTerm(newValue) {
      // React to the updated search term
      this.loadProducts(newValue);
    }
  },
  methods: {
    loadProducts(term) {
      // Example API call (e.g., repository search)
      // this.productRepository.search(criteria, Shopware.Context.api)
    }
  }
}
```

Whenever `searchTerm` changes, the watcher executes and reloads the product list. This is a common use case in the administration.

As you can see, the name of watcher (`searchTerm`) must match the property it watches.

**Example: Watching nested objects (deep watchers):**

Some values in the administration, such as Criteria, filters, or entities, are objects with many nested properties. Vue does **not** detect changes inside nested objects unless you explicitly enable **deep mode**.

```js
export default {
  data() {
    return {
      criteria: this.createCriteria(),
      products: []
    };
  },
  watch: {
    criteria: {
      handler(){
        // Reload listing whenever any part of the criteria changes
        this.loadProducts();
      },
      deep: true
    }
  },
  methods: {
    createCriteria() {
      const criteria = new Shopware.Data.Criteria();
      criteria.setPage(1);
      criteria.setLimit(25);
      return criteria;
    },
    loadProducts() {
      this.productRepository
        .search(this.criteria, Shopware.Context.api)
        .then(result => {
          this.products = result;
        });
    }
  }
}
```

This pattern is extremely common in the Shopware administration because listings often use Criteria objects for filters, sorting, and pagination.

**Example: Watching route parameters:**

When building the administration modules with detail pages, it is common to reload data when the route changes (e.g., switching to another product ID).

```js
export default {
  watch: {
    '$route.params.id'(newId) {
      this.loadDetail(newId);
    }
  }
}
```

This pattern is used in detail pages to reload the detail information when the route changes.

For more information about watchers, check the documentation from [W3Schools](https://www.w3schools.com/vue/ref_opt_watch.php) and the official [Vue documentation](https://vuejs.org/api/options-state.html#watch).

### Emits

The `emits` option defines which **custom events** a component can emit and send to its parent. It makes event communication explicit and improves readability and predictability.

**Basic example: Emitting a simple event:**

Child component:

```js
export default {
  emits: ['increment'],
  
  methods: {
    increment() {
      this.$emit('increment');
    }
  }
}
```

And in the parent component, you can listen for it:

```twig
<custom-button @increment="increaseCounter" />
```

**Real-World example 1: Passing data to the parent:**

Child component:

```js
export default {
  emits: ['update:value'],

  methods: {
    onChange(event) {
      const newValue = event.target.value;
      this.$emit('update:value', newValue); // Sends the new value to the parent
    }
  }
}
```

Template of the child component:

```twig
<input type="text" @input="onChange" />
```

Parent usage:

```twig
<custom-input @update:value="setValue" />
```

Parent component:

```js
export default {
  data() {
    return {
      value: ''
    };
  },

  methods: {
    setValue(newValue) {
      this.value = newValue;
    }
  }
}
```

This pattern is used widely in configuration components, custom field editors, and form elements.

**How it works:**

1. The child listens to a DOM event (in this case `@input`)
2. The child's method emits a custom event (`@update:value`) with the new value as payload
3. The parent receives the event and updates its state

**Real-World example 2: Notify parent about list item selection:**

```js
export default {
  emits: ['select-item'],
  
  methods: {
    select(item) {
      this.$emit('select-item', item);
    }
  }
}
```

Parent usage:

```twig
<item-list @select-item="openDetail" />
```

This is common in list/detail setups where selecting an item should open a detail page or update another part of the UI.

---

Emits are a recommended way for **child-to-parent communication** instead of accessing `$parent` directly. Use `emits` whenever a child component needs to **notify** its parent about something: a click, a selection, or an updated value.

<Callout title="Emits in Child-Parent Communication" type="info">

Native HTML elements such as `<button>` and `<input>` can only emit **native DOM events** such as `@click`, `@input`, `@change`, etc.

Custom emits require a **custom Vue component**. This is why the parent examples above use custom elements such as `custom-input` and `item-list`.

</Callout>

## Summary

In this learning unit, you explored the **state-related options** of the Vue 3 Options API, which form the foundation of data flow and component behavior.

You know understand:

- How `props` pass data from parent to child
- How `data` stores local component state
- How `computed` efficiently derives values
- How `methods` perform actions
- How `watchers` react to changes
- How `emits` enable clean child-to-parent communication

Very Well! With this knowledge, you can already build stable and predictable components!

In the next learning unit, you will explore additional Options API features – including `inject`, `inheritAttrs`, local components, and the key lifecycle hooks.
