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

# Query Parameters

In this guide, you’ll learn how to read and set query parameters in a Vaadin view, and how to bind a field to a query parameter with a [signal](https://vaadin.com/docs/next/flow/ui-state.md) so the two stay in sync.

## <a id="copy-paste-into-your-project"></a>Copy-Paste into Your Project

If you want to quickly try out query parameters in your Vaadin application, copy-paste the following code into a new Java class named `QueryParameterView` in your project’s main package:

`QueryParameterView.java`

```java
@Route("building-apps/pass-data/query-parameter")
public class QueryParameterView extends VerticalLayout {

    private static final String QUERY_PARAM_FILTER = "filter";

    // Read the query parameter reactively from the router state signal
    private final Signal<String> filterParam = () -> UI.getCurrentOrThrow()
            .routerStateSignal().get().location().getQueryParameters()
            .getSingleParameter(QUERY_PARAM_FILTER).orElse("");

    QueryParameterView() {
        var filterField = new TextField("Filter");
        add(filterField);

        // Two-way binding: the field shows the current value, and edits
        // update the URL through setFilter()
        filterField.bindValue(filterParam, this::setFilter);
    }

    private void setFilter(String filter) {
        var queryParameters = UI.getCurrentOrThrow().getActiveViewLocation()
                .getQueryParameters().merging(QUERY_PARAM_FILTER, filter);
        UI.getCurrentOrThrow().navigate(QueryParameterView.class,
                queryParameters);
    }
}
```

This view reads the `filter` query parameter from the router state signal and two-way binds it to a text field: the field shows the current value, and editing it updates the URL. For more detailed instructions on how to use query parameters, continue reading below.

## <a id="what-are-query-parameters"></a>What Are Query Parameters?

Query parameters are key-value pairs appended to the end of a URL after a `?` character. Multiple parameters are separated by `&`.

For example, this URL: `/orders?sort=date&filter=shipped`

Contains the following query parameters:

- `sort` → `"date"`

- `filter` → `"shipped"`

Query parameters are commonly used to store view-related state, such as a grid’s sort order or a search field’s value. Since they are optional, always provide default values when a parameter is missing.

> **Tip:** If you need required parameters, consider using [route parameters](https://vaadin.com/docs/next/building-apps/views/pass-data/route-parameters.md) instead.

## <a id="reading-query-parameters-reactively"></a>Reading Query Parameters Reactively

Query parameters are part of the current location, which is available as a [signal](https://vaadin.com/docs/next/flow/ui-state.md). Calling `UI.getCurrentOrThrow().routerStateSignal()` returns a read-only signal whose value is a `RouterState` record; its `location()` method gives you the `Location`, and `getQueryParameters()` the `QueryParameters` for the active navigation.

As with [route templates](https://vaadin.com/docs/next/building-apps/views/pass-data/route-templates.md#accessing-route-parameter-values), a convenient pattern is to derive a separate signal for each parameter. Because `Signal` is a functional interface, you can define one with a lambda that reads the value from the location:

```java
private static final String QUERY_PARAM_FILTER = "filter"; // (1)

private final Signal<String> filterParam = () -> UI.getCurrentOrThrow()
        .routerStateSignal().get().location().getQueryParameters()
        .getSingleParameter(QUERY_PARAM_FILTER).orElse("");
```

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

Bind components to these parameter signals as you would to any other signal. Reading the value inside a binding’s reactive context makes the component update automatically whenever the parameter changes.

The `QueryParameters` class provides methods for accessing query parameter values; familiarize yourself with its API if you use query parameters often. Since query parameters are always strings and always optional, they may be missing or contain invalid data, so always supply a default with `orElse()` and validate as needed.

> **Note:** If you need to inspect query parameters imperatively — for example, to redirect before the view renders — implement `BeforeEnterObserver` and read `event.getLocation().getQueryParameters()` inside `beforeEnter()`.

## <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/next/building-apps/views/navigate.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.getCurrentOrThrow().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.

When you navigate by location string, the query string can also be part of the string itself, which is handy for a link that’s already assembled — one that comes from a mail template or an external system, for example. The query string is parsed into the `QueryParameters` of the resulting location, so the view reads it the same way either way: (since V25.3)

```java
UI.getCurrentOrThrow().navigate("orders?filter=late&sort=due");
```

The string form and a separate `QueryParameters` object are alternatives, not a combination: `navigate(String, QueryParameters)` throws an `IllegalArgumentException` if the location carries a query string or a fragment of its own while the parameters aren’t empty, since the ones in the string would be lost. A location that consists only of a fragment, such as `"#totals"`, identifies no route and is passed on to the client router as it is.

## <a id="binding-a-field-to-a-query-parameter"></a>Binding a Field to a Query Parameter

Query parameters often back a form field directly — a filter, a search term, or a sort option. With the parameter exposed as a signal, you can two-way bind a field to it using `bindValue()`: the field shows the current value, and edits write back to the URL.

```java
filterField.bindValue(filterParam, this::setFilter); // (1)

private void setFilter(String filter) {
    var queryParameters = UI.getCurrentOrThrow().getActiveViewLocation()
            .getQueryParameters()
            .merging(QUERY_PARAM_FILTER, filter); // (2)
    UI.getCurrentOrThrow().navigate(QueryParameterView.class, queryParameters);
}
```

1. `filterParam` is the parameter signal from [Reading Query Parameters Reactively](#reading-query-parameters-reactively); `setFilter()` is called whenever the field changes.

2. `merging()` replaces only the `filter` parameter and leaves any others in the URL intact.

When the user edits the field, `setFilter()` navigates the view to itself with the updated query parameters. The existing view instance is reused, the browser URL updates, and the router state signal — and therefore the bound field — reflects the new value. The binding works in both directions, so the field also updates if the URL changes by other means, such as the browser’s back button.

`merging()` preserves the other parameters: if the URL was `/orders?sort=date&filter=shipped` and the user enters "foobar", it becomes `/orders?sort=date&filter=foobar`.
