---
title: "Element states"
description: "Style elements per state, and use a condition to disable an element at runtime."
---

Interactive flow elements change their look based on user actions: a tapped quiz option becomes **Selected**, a focused input becomes **Active**. Some states are condition-driven — for example, you can **disable** a button. Style each state separately to give users visual feedback without app code.

<div style={{
  maxWidth: '560px',
  margin: '0 auto 2rem',
  position: 'relative',
  aspectRatio: '16/9',
  width: '100%'
}}>
  <iframe
    style={{
      position: 'absolute',
      top: 0,
      left: 0,
      width: '100%',
      height: '100%'
    }}
    src="https://www.youtube.com/embed/gdsNfHpKAqQ?si=VY5mqZgH1j0RB6fE"
    title="YouTube video player"
    frameBorder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerPolicy="strict-origin-when-cross-origin"
    allowFullScreen
  />
</div>

## Available states by element kind

| Element kind | Built-in states | Addable states |
|---|---|---|
| [Selectable elements](#selectable-element-states) | **Default**, **Selected** | **Disabled** |
| [Inputs](#input-states) | **Default**, **Active**, **Invalid** | **Disabled** |
| [Any element with a tap interaction](#condition-driven-disabled-state) — buttons, images, icons, stacks, and so on | **Default** | **Disabled** |
| [Progress indicator steps](#step-states-for-progress-indicators) | **Completed**, **Current**, **Upcoming** | — |

**Addable** states don't appear by default — open **States settings** Settings to add them. They are [**condition-driven**](#condition-driven-disabled-state): you define when they activate.

## How to style a state

1. Select an element. The **States** section in the right panel lists the states the element supports.
2. In the **States** section, activate the target state. Add the [condition-driven Disabled state](#condition-driven-disabled-state) if needed.
3. Change any property — fill, border, typography, text content, and so on. The change is scoped to that state. 

    Nested elements become stateful alongside the parent. Any change to a child — colors, layouts, text content — is scoped to the parent's active state.

4. The Builder applies the matching style at runtime.

:::tip
A state can change *what* a text element says, not just how it looks. The Builder treats text content as a property, same category as fill or border width.
:::

## Selectable element states

Selectable elements — quiz options, products, tabs, trial toggles, and any [custom selectable element](flow-selectable-elements#make-an-element-selectable) — have two states out of the box:

- **Default**: The element's resting appearance.
- **Selected**: Applies when the user taps the element. The Builder reverts to Default when the user de-selects the element.

In a single-choice group, selecting one element de-selects the others. Multi-choice groups let several be Selected at the same time. Toggles are independent — selecting one has no effect on its siblings. See [group types](flow-selectable-elements#group-types).

:::tip
Need to style the same state for several elements (for example, quiz options)? Style one element first, then duplicate it. State styling doesn't carry over between siblings — duplication is the current workaround.
:::

## Input states

- **Default**: The input's resting appearance.
- **Active**: Applies while the input is focused.
- **Invalid**: Applies when the input's content fails validation. For example, when an email field doesn't contain `@`. See [Input validation](builder-inputs-and-forms#input-validation).
- **Disabled**: The input is not interactive. Add this state manually; see [Condition-driven Disabled state](#condition-driven-disabled-state).

Style each state the same way as a selectable element: activate the target state, change properties.

## Condition-driven Disabled state

The Disabled state prevents the user from interacting with an element. Unlike Default, Selected, Active, or Invalid, the Disabled state does not activate on its own — it requires a user-defined trigger condition.

Disabled is available on:

- **Inputs**: Any [input field](builder-inputs-and-forms) — text, email, password, number, phone, date and/or time.
- **Selectable elements**: Quiz options, products, tabs, trial toggles, and any [custom selectable element](flow-selectable-elements#make-an-element-selectable).
- **Any element with a tap interaction**: For example, a button, image, or icon that triggers a navigation action.

### Add the Disabled state

To add and configure a Disabled state:

1. Select the target element.
2. In the **States** section, click **Settings** Settings.
3. Choose **Add Disabled state**. The Disabled state appears in the **States** section.
4. Next to the new Disabled state, click **Edit conditional state** Edit conditional state.
5. Add a condition. If you want to disable the **submit** button unless the input passes validation, compare the input's `isValid` variable to `false`.
6. Style the Disabled state to visually communicate the restriction (for example, lower the opacity).

{ }

The Adapty SDK evaluates the condition at runtime and applies the Disabled state when appropriate — no app code needed.

## Step states for progress indicators

:::link
Main article: [Progress indicators](builder-loaders-and-progress-bars#step-states)
:::

Progress indicators show users how far they've gotten in an onboarding flow. Each step has three states:

- **Completed**: Steps the user has passed.
- **Current**: The user's current step.
- **Upcoming**: Steps the user hasn't reached yet.