> Markdown version of [Flow](https://vaadin.com/docs/v24/building-apps/views/pass-data/query-parameters/flow). Section index: [llms.txt](https://vaadin.com/docs/v24/building-apps/llms.txt)

# Query Parameters in Flow

In this guide, you’ll learn how to access and set query parameters in a Flow view. A mini-tutorial at the end will help you apply these concepts in a real Vaadin application.

## <a id="accessing-query-parameter-values"></a>Accessing Query Parameter Values

You access query parameters similarly to [multiple route parameters](https://vaadin.com/docs/v24/building-apps/views/pass-data/route-templates.md#accessing-route-parameter-values). Your view must implement the `BeforeEnterObserver` interface, which defines the `beforeEnter()` method. Inside this method, you can retrieve query parameters:

```java
@Route
public class OrdersView extends Main implements BeforeEnterObserver {

    private static final String QUERY_PARAM_SORT = "sort"; // (1)
    private static final String QUERY_PARAM_FILTER = "filter";

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        event.getLocation().getQueryParameters().getSingleParameter(QUERY_PARAM_SORT)
            .ifPresent(sort -> {
                // Process the sort parameter
            });
        event.getLocation().getQueryParameters().getSingleParameter(QUERY_PARAM_FILTER)
            .ifPresent(filter -> {
                // Process the filter parameter
            });
    }
    ...
}
```

1. **Tip:** To improve readability and maintainability, declare query parameter names as constants.

Now, if you navigate to `/orders?sort=date&filter=shipped`, the query parameter values will be:

- `sort` → `"date"`

- `filter` → `"shipped"`

The `QueryParameters` class provides methods for accessing query parameter values. Familiarize yourself with its API if you frequently use query parameters in your application.

> **Note:** You can also retrieve query parameters using `UI.getCurrent().getActiveViewLocation().getQueryParameters()`.

Since query parameters are always strings and optional, they may be empty or contain invalid data. To handle this, you can provide default values, redirect users to a different view, or display an error message.

## <a id="setting-query-parameters"></a>Setting Query Parameters

The `QueryParameters` class is immutable, meaning you can’t modify existing query parameters. Instead, you must create a new `QueryParameters` object and pass it to `UI.navigate()`. Query parameters are set when navigating to a view.

In the following example, `OrdersView` provides a [custom API](https://vaadin.com/docs/v24/building-apps/views/navigate/flow.md#your-own-api) for navigating to itself while setting the `filter` query parameter:

```java
@Route
public class OrdersView extends Main implements BeforeEnterObserver {

    private static final String QUERY_PARAM_SORT = "sort";
    private static final String QUERY_PARAM_FILTER = "filter";

// tag::snippet[]
    public static void showOrders(@Nullable String filter) {
        var queryParameters = filter == null ? QueryParameters.empty()
            : QueryParameters.of(QUERY_PARAM_FILTER, filter);
        UI.getCurrent().navigate(OrdersView.class, queryParameters);
    }
// end::snippet[]
    ...
}
```

> **Important:** You *cannot* set query parameters to `null`. To clear a query parameter, exclude it from the `QueryParameters` object.

### <a id="updating-query-parameters-dynamically"></a>Updating Query Parameters Dynamically

Query parameters are often set dynamically, such as when users apply filters or change sort options. In such cases, the view must navigate to itself while updating query parameters.

When navigating to the *same* view, the existing view instance is reused. The browser URL updates, and `beforeEnter()` is invoked again.

The following example updates the `filter` query parameter when a user types in a text field:

```java
@Route
public class OrdersView extends Main implements BeforeEnterObserver {

    private static final String QUERY_PARAM_SORT = "sort";
    private static final String QUERY_PARAM_FILTER = "filter";

// tag::snippet[]
    public OrdersView() {
        var filterField = new TextField();
        add(filterField);

        filterField.addValueChangeListener(event -> {
            var queryParameters = UI.getCurrent().getActiveViewLocation()
                .getQueryParameters()
                .merging(QUERY_PARAM_FILTER, event.getValue());
            UI.getCurrent().navigate(OrdersView.class, queryParameters);
        });
    }
// end::snippet[]
    ...
}
```

If the original URL was `/orders?sort=date&filter=shipped`, and the user enters "foobar" in the text field, the URL updates to `/orders?sort=date&filter=foobar`.

## <a id="try-it"></a>Try It

In this mini-tutorial, you’ll create a view that accesses and dynamically updates two query parameters.

Set Up the Project

First, generate a [walking skeleton with a Flow UI](https://vaadin.com/docs/v24/getting-started/start.md), [open](https://vaadin.com/docs/v24/getting-started/import.md) it in your IDE, and [run](https://vaadin.com/docs/v24/getting-started/run.md) it with hotswap enabled.

Create the View

Create a new package `[application package].tutorial.ui.view`. Then, create a class named `QueryParameterView`:

QueryParameterView\.java

```java
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.Route;

@Route
public class QueryParameterView extends Main implements BeforeEnterObserver {

    private static final String QUERY_PARAMETER_TEXT = "text";
    private static final String QUERY_PARAMETER_CHECK = "check";

    private final TextField textField;
    private final Checkbox checkbox;

    public QueryParameterView() {
        textField = new TextField();
        checkbox = new Checkbox();
        add(textField, checkbox);
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
    }
}
```

Open your browser and navigate to: <http://localhost:8080/queryparameter>

You should see an empty text field and an unchecked checkbox.

Access Query Parameters

Modify the `beforeEnter()` method to populate the components:

```java
@Override
public void beforeEnter(BeforeEnterEvent event) {
    var queryParameters = event.getLocation().getQueryParameters();
    queryParameters.getSingleParameter(QUERY_PARAMETER_TEXT)
        .ifPresent(textField::setValue);
    queryParameters.getSingleParameter(QUERY_PARAMETER_CHECK)
        .map(Boolean::parseBoolean).ifPresent(checkbox::setValue);
}
```

Navigate to: <http://localhost:8080/queryparameter?text=hello+world&check=true>

The text field should now contain `"hello world"` and the checkbox should be checked.

Update the `text` Query Parameter

Modify the constructor to update the query parameter dynamically:

```java
public QueryParameterView() {
    textField = new TextField();
// tag::snippet[]
    textField.setValueChangeMode(ValueChangeMode.LAZY); // (1)
    textField.addValueChangeListener(event -> {
        var queryParameters = UI.getCurrent().getActiveViewLocation()
            .getQueryParameters().merging(QUERY_PARAMETER_TEXT, event.getValue());
        UI.getCurrent().navigate(QueryParameterView.class, queryParameters);
    });
// end::snippet[]
    checkbox = new Checkbox();
    add(textField, checkbox);
}
```

1. The field updates 400 ms after the user stops typing.

Try changing the text field value in the browser. The URL updates automatically.

Update the `check` Query Parameter

Add a listener for the checkbox:

```java
public QueryParameterView() {
    textField = new TextField();
    textField.setValueChangeMode(ValueChangeMode.LAZY); // (1)
    textField.addValueChangeListener(event -> {
        var queryParameters = UI.getCurrent().getActiveViewLocation()
            .getQueryParameters()
            .merging(QUERY_PARAMETER_TEXT, event.getValue());
        UI.getCurrent().navigate(QueryParameterView.class, queryParameters);
    });
    checkbox = new Checkbox();
// tag::snippet[]
    checkbox.addValueChangeListener(event -> {
        var queryParameters = UI.getCurrent().getActiveViewLocation()
            .getQueryParameters()
            .merging(QUERY_PARAMETER_CHECK, event.getValue().toString());
        UI.getCurrent().navigate(QueryParameterView.class, queryParameters);
    });
// end::snippet[]
    add(textField, checkbox);
}
```

Try toggling the checkbox. The URL updates automatically while preserving the `text` parameter.

Final Thoughts

You’ve now successfully implemented query parameters in Flow. You learned how to:

- Access query parameter values.

- Update query parameter values dynamically.

Next, try modifying the code to:

- Use `1` and `0` instead of `true` and `false` for the `check` parameter.

- Validate the `text` query parameter to allow only **letters, digits and whitespace**.

You’re now ready to use query parameters in real Vaadin applications!
