# How to Use FlutterFlow Data Binding to Connect UI to Data

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 20-30 min
- Compatibility: FlutterFlow Free+
- Last updated: March 2026

## TL;DR

FlutterFlow data binding wires query results to widget properties through the Set from Variable menu. Click any widget property (text, image URL, color, visibility) and choose a source: Backend Query result, Page State, App State, Component Parameter, or Global Properties. Use Generate Dynamic Children to bind a list result to a ListView. Conditional Value creates ternary expressions for dynamic content. Data flows only downward through the widget tree to children.

## Connect your database, API calls, and state variables to every pixel of your FlutterFlow UI

Data binding is the most important skill in FlutterFlow — it is the bridge between your database queries and your visible UI. Without it, your app displays static placeholder text no matter what is in your database. This tutorial walks through all five data binding sources in FlutterFlow: Backend Query results, Page State variables, App State variables, Component Parameters, and Global Properties. You will learn how data flows down the widget tree, why binding fails when you try to access data from the wrong scope, how to render dynamic lists, and how to use Conditional Values to change widget appearance based on data.

## Before you start

- A FlutterFlow project with at least one collection defined in Firestore or a Supabase table, OR an API Manager call configured
- At least one page created with some widgets (Text, Image, ListView) that you want to bind data to
- Test data in your database (use FlutterFlow's Content Manager to add 3-5 documents)
- Basic familiarity with adding widgets to the FlutterFlow canvas

## Step-by-step guide

### 1. Add a Backend Query to a page and understand data scope

Data binding begins with a data source. The most common source is a Backend Query — a database read operation attached to a widget or page. To add one: select the page (click the page name in the widget tree, not a widget on the page) → in the Properties Panel on the right, scroll to Backend Query → click Add Query. Choose Firestore (or Supabase if connected) → select your collection → set Query Type to List of Documents if you want multiple records, or Single Document for one record. Set your filters, ordering, and limit. Click Confirm. The Backend Query is now attached to the page — its result is available to every widget that is a descendant of the page in the widget tree. This is the core data scoping rule: Backend Query results flow DOWNWARD in the widget tree. A query on the page is available to all widgets on that page. A query on a Column is only available to widgets inside that Column. A query on a ListView is only available inside the ListView's child template. Understanding this hierarchy prevents the most common data binding errors.

**Expected result:** Backend Query appears in the Properties Panel for the page. You can see the query configuration showing the collection, filters, and ordering.

### 2. Bind widget properties using Set from Variable

With a Backend Query in place, you can bind any widget property to the query result. Select a Text widget on the page. In the Properties Panel → Text → click the orange lightning bolt icon (or the Set from Variable option) next to the text value. This opens the Variable Picker. Under Source, select Backend Query Record → your collection name → select the field you want (e.g., title, name, email). The text widget now displays the value of that field from the query result. The orange bolt icon appears on properties that are currently bound to a variable — static values show a plain text input. You can bind almost every widget property: Text value, Image URL (network image path), Color (using a Hex Code stored in Firestore), Visibility (a Boolean field), Width, Height, Padding. Try binding an Image widget's Network Path to a field storing an image URL — click the image widget → Network Image → Set from Variable → Backend Query → your imageUrl field. The image now loads the URL stored in your database.

**Expected result:** Text and Image widgets on the page display actual data from your Firestore collection instead of placeholder values.

### 3. Use Generate Dynamic Children to render lists from query results

When your Backend Query returns a list (Query Type: List of Documents), you need to render one child widget per item in the list. The Generate Dynamic Children feature handles this. First add a ListView widget to your page (not a Column — ListView handles scrolling and is the correct choice for database-backed lists). Select the ListView. In Properties Panel, click Generate Dynamic Children. The picker asks: what list should generate the children? Select Backend Query Result → your collection → this creates one child widget per document. Now select the auto-generated child Column inside the ListView. Inside this child Column, add a Text widget and an Image widget. When you use Set from Variable on these child widgets, the Variable Picker shows the fields for a single list item — e.g., 'Current Document in List'. Select Current Document in List → title for the Text, Current Document in List → imageUrl for the Image. FlutterFlow will render one Card per document, automatically populating each with that document's data. The ListView scrolls as needed and FlutterFlow adds pagination support through Backend Query limit and loadMore settings.

**Expected result:** The ListView renders one item per database document, with each item showing that document's title, image, and other bound fields.

### 4. Create Page State variables for temporary UI data

Page State variables store temporary data that exists only while the user is on that page — selected filter, toggle state, counter value, selected item from a list. They are not stored in the database. To add one: select the page → Properties Panel → State Variables → Add Field. Name it (e.g., selectedTab, isFilterOpen, selectedItemId) and choose a type (String, Integer, Boolean, Document Reference, etc.). Give it an initial value. Now you can bind widget properties to Page State: click a widget property → Set from Variable → Page State → your variable name. To update Page State: add an Action to a button → Update Page State → select the variable → set a new value. Example: a ChoiceChips filter widget with three options (All, Active, Inactive). On selection change → Update Page State selectedStatus = selected chip value. The Backend Query on the page has a filter: status == selectedStatus Page State variable. When the user taps a chip, the Backend Query re-runs with the new filter, and the ListView updates — all without any server-side code.

```
// Page State variables for a filtered product listing page
// Add these in Properties Panel → State Variables:
//
// selectedCategory: String   Initial: 'All'
// isLoading: Boolean         Initial: false
// selectedProductId: String  Initial: ''
// sortOrder: String          Initial: 'newest'
//
// Backend Query on the page:
// Collection: products
// Filter: IF selectedCategory != 'All'
//           THEN category == selectedCategory (Page State)
// OrderBy: createdAt Descending (when sortOrder == 'newest')
//          price Ascending (when sortOrder == 'price_asc')
// Note: use Conditional Value for dynamic orderBy:
//   if sortOrder == 'newest' → createdAt
//   else → price
//
// ChoiceChips binding:
//   Options: ['All', 'Electronics', 'Clothing', 'Books']
//   Initial Selected: selectedCategory (Page State)
//   On Selection Change → Update Page State selectedCategory = selectedOption
```

**Expected result:** Tapping a filter chip updates the Page State variable, triggering the Backend Query to re-run with the new filter and the ListView to refresh with filtered results.

### 5. Use Conditional Value and App State for advanced binding patterns

Conditional Value lets you return different data based on a condition — it is a ternary expression you build visually in FlutterFlow without writing code. Click a widget property → Set from Variable → Conditional Value. Set: if [condition] → value A, else → value B. Example: a status badge on an order card. Color: if orderStatus == 'delivered' → Color(0xFF4CAF50) green, else → Color(0xFFFF9800) orange. Text: if orderStatus == 'pending' → 'Awaiting payment', else if orderStatus == 'shipped' → 'On the way', else → 'Delivered'. App State variables work like Page State but persist across all pages and remain as long as the app is running. Add App State variables: Settings → App State → Add Field. Common uses: current user's cart items (List of JSON), notification count (Integer), selected theme (String). Bind any widget to App State the same way as Page State — Set from Variable → App State → field name. Update App State with an Action: Update App State. A common pattern: when the user adds an item to their cart on a ProductDetail page, Update App State cartCount += 1, and the cart icon in the AppBar shows a Badge bound to App State cartCount.

**Expected result:** Status badges show different colors based on the data value. The cart badge in the AppBar updates in real-time when items are added across different pages.

### 6. Bind Component Parameters to reuse components with different data

FlutterFlow Components are reusable widget groups — a ProductCard, a UserAvatar, a NotificationItem. When you create a Component and place it on multiple pages, each instance needs different data. Component Parameters let the parent pass data down to the component. To add a parameter: open the Component → Properties Panel → Parameters → Add Parameter. Name it (productName, imageUrl, price) and choose a type. Inside the component, bind the Text widget to Component Parameters → productName. Now on any page where you use this Component, you see a parameter input area in the Properties Panel: set productName = Current Document in List → title. Each instance of the component displays different data from the list. This is the correct way to build list items — create a Component with parameters, place it as the Generate Dynamic Children template, and pass list item fields as parameters. Components also accept Document Reference parameters: pass the entire document reference to the component, then inside the component run a separate Backend Query using that reference to fetch the full document.

**Expected result:** A single ProductCard component renders correctly across 3 different pages and in a ListView, each showing different data based on the parameters passed to it.

## Complete code example

File: `Data Binding Reference Guide`

```text
Five Data Binding Sources in FlutterFlow
==========================================

1. Backend Query Result
   Where: attached to page, widget, or component
   Access: only in descendant widgets (flows DOWN)
   Picker path: Backend Query Record → {collection} → {field}
   Use for: displaying database content

2. Page State Variables
   Where: defined on the page, lives only during page session
   Access: any widget on the same page
   Picker path: Page State → {variableName}
   Update: Action → Update Page State
   Use for: selected tab, filter value, toggle state, temp counter

3. App State Variables
   Where: Settings → App State (global)
   Access: any widget in any page
   Picker path: App State → {variableName}
   Update: Action → Update App State
   Use for: cart count, notification count, user preferences, auth state

4. Component Parameters
   Where: defined on Component, passed when placed on a page
   Access: inside the component only
   Picker path: Component Parameters → {paramName}
   Use for: reusable cards, list items, modal contents

5. Global Properties
   Where: built-in, no configuration needed
   Examples:
     Current User → uid, email, displayName, photoUrl
     Current Time → DateTime
     Device Info → platform, screen width/height, locale
   Picker path: Global Properties → {property}
   Use for: personalization, responsive layout, time-based content

Key Data Binding Patterns
==========================

List Rendering:
  Page → Backend Query (List of Documents)
  └── ListView → Generate Dynamic Children
      └── Child Column
          ├── Image (Set from Variable → Current Doc → imageUrl)
          └── Text (Set from Variable → Current Doc → title)

Conditional Display:
  Container → Visibility
    Conditional Value:
      if userRole == 'admin' → true
      else → false

Dynamic Color:
  Container → Background Color
    Conditional Value:
      if status == 'active' → #4CAF50 (green)
      else → #FF9800 (orange)

Pass-through (page → component):
  ListView item → ProductCard Component
    productName = Current Doc → title
    price = Current Doc → price
    imageUrl = Current Doc → imageUrl

Scope Rule (most important):
  Backend Query on PAGE → available to ALL widgets on page
  Backend Query on CONTAINER → ONLY available inside that container
  NEVER accessible in sibling/parent widgets
```

## Common mistakes

- **Binding a widget to a Backend Query result from a query that is not its ancestor in the widget tree** — Backend Query results flow only DOWNWARD in the widget tree — from parent to children. If you have a Backend Query on a Column and try to bind a Text widget that is outside (a sibling column, or a parent row), the Variable Picker will not show that query's result. This is by design — it prevents unpredictable data access across unrelated widget branches. Fix: Move the widget that needs the data INSIDE the widget that has the Backend Query, or move the Backend Query to a higher common ancestor that contains all the widgets needing the data. If both widgets are siblings, add the Backend Query to their parent Container or the page itself.
- **Using App State to store data that should be Page State, causing stale data from a previous page session to appear on re-visit** — App State persists for the entire app session. If you store a selected filter in App State and the user navigates away and comes back, the old filter value is still set — the page shows filtered results without the user consciously choosing to filter. This confuses users who expect a fresh page state on navigation. Fix: Use Page State for data that should reset when the user navigates away: selected tabs, filter values, form inputs, toggle states, error messages. Use App State only for data that intentionally persists: cart contents, notification counts, user preferences, authentication state.
- **Placing a Backend Query on a Text widget instead of a Container or the page, thinking it will display just that one field** — When you put a Backend Query on a Text widget, the query binds to the Text widget — but the Text widget is a leaf node with no children. You cannot have a Backend Query that also has Generate Dynamic Children on a Text widget. The query runs but the result is only available to that specific Text widget, not to sibling Images or other widgets you want to populate with the same data. Fix: Place the Backend Query on a Container or Column that wraps ALL the widgets needing that data. Put an Image, a Text for title, a Text for description, and a Button inside the Container. Bind each widget's properties to the Container's Backend Query result using Set from Variable.

## Best practices

- Add Backend Queries at the lowest widget level that still covers all consuming children — avoid page-level queries that fetch data for only one small section of the page
- Use the orange lightning bolt icon as a visual signal: if it is grey, the property is static; if it is orange, it is data-bound — scan your widgets for grey bolts on properties that should be dynamic
- Name Page State and App State variables descriptively (selectedCategoryFilter, cartItemCount) — cryptic names like var1 cause confusion when your app grows past 10 pages
- Prefer Component Parameters over directly querying a Database in each list item — pass the data down from the parent list query rather than running N separate queries for N list items
- Use Conditional Value for computed display properties (colors, labels, visibility) rather than adding multiple duplicate widgets with different visibility conditions
- Test data binding in Run mode on a physical device, not just in FlutterFlow's browser preview — some binding edge cases only appear in the compiled app
- For list items that need more data than the list query provides, use a Component with a DocumentReference parameter and a Backend Query inside the component — this is the correct pattern for detail-rich list items

## Frequently asked questions

### Why is my Text widget showing an empty string even though the Firestore document has data?

Three likely causes: (1) The Backend Query is not an ancestor of the Text widget — the query is on a sibling or unrelated widget branch, so its result is not in scope. Move the Backend Query to a parent Container that wraps the Text widget. (2) The field name in the binding is misspelled or has the wrong case — Firestore field names are case-sensitive. 'Title' and 'title' are different fields. (3) The query filter is excluding the document — test the same filter in Firebase Console to confirm the document appears.

### What is the difference between Page State and App State?

Page State exists only while the user is on that page — it resets to initial values every time the user navigates away and back. Use it for: selected tab, current filter, form field values, expansion state of an accordion. App State persists for the entire app session (until the app is force-closed) — it is global and accessible from any page. Use it for: cart item count, user's selected theme, notification count, anything that should survive page navigation.

### How do I bind a widget to the currently logged-in user's data?

Add a Backend Query on the page with Query Type: Single Document, Collection: users, where Document ID equals Current User UID (from Global Properties → Current User → UID). This fetches the logged-in user's document. Bind widgets to this query: Text → Backend Query Record → users → displayName, Image → Backend Query Record → users → avatarUrl. Alternatively, some user fields are available directly via Global Properties → Current User without a database query: email, uid, displayName from Firebase Auth.

### Can I bind a widget property to the result of a calculation?

Yes, using Custom Functions. Create a Custom Function that takes one or more input values and returns a computed result. For example, a formatPrice Custom Function that takes a Double and returns a formatted String '$29.99'. In the Set from Variable picker, select Custom Function → formatPrice → pass the price field as the argument. Custom Functions are evaluated at build time and their result can be bound to any widget property. For simpler calculations, Conditional Value supports basic comparisons without writing a Custom Function.

### How do I update a specific item in a list when the user taps it?

Use the selected item's Document Reference. When the user taps a list item, store the tapped item's document reference in a Page State variable (type: DocumentReference). Add an Update Document Action to write the new value to Firestore using that reference. The real-time Backend Query on the page automatically refreshes when Firestore data changes, so the updated item appears immediately in the list without a page reload.

### Why does Generate Dynamic Children show the same data in every list item?

This happens when the child widget is bound to the parent page's Backend Query instead of 'Current Document in List'. Inside the Generate Dynamic Children template, the Variable Picker should show 'Current Document in List' as a source — this represents the single current item being rendered, not the full list. If you accidentally bound to the page-level query (which returns the full result or first document), all list items show identical data. Re-open Set from Variable on each child widget and select Current Document in List → field name.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-use-flutterflow-s-data-binding-to-connect-your-app-s-ui-to-its-data
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-use-flutterflow-s-data-binding-to-connect-your-app-s-ui-to-its-data
