> Markdown version of [Hilla](https://vaadin.com/docs/next/flow/integrations/hilla). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Flow-Hilla Hybrid Applications

Hilla, which is part of Vaadin, is used for building Reactive web applications on Java backends. It integrates seamlessly a [React](https://reactjs.org/) TypeScript frontend with a [Spring Boot](https://spring.io/projects/spring-boot) backend.

You can develop hybrid applications that leverage Vaadin Flow and Hilla features. This allows you to combine in one application, Vaadin Flow routes written in pure Java with the Hilla ones written in React. This page shows how [to add Hilla to an existing Vaadin Flow application](#hilla-to-flow). And it includes the reverse: how [to add Flow views to an application that has Hilla views](#flow-to-hilla).

See the [source code for a complete Vaadin Flow-Hilla application](https://github.com/vaadin/flow-hilla-hybrid-example).

## <a id="hilla-to-flow"></a>Add Hilla to Flow Applications

To add Hilla to a Vaadin Flow application, you could start with a Spring Boot-based Vaadin Flow application (e.g., [skeleton-starter-flow-spring](https://github.com/vaadin/)). You would add Hilla to the project using the steps described in the sub-sections here.

Start by adding the Hilla Spring Boot starter to the project, as described in [Enabling Browser-Callable Services in a Vaadin Project](https://vaadin.com/docs/next/hilla/guides/browser-callable-services.md#enabling). No other build configuration is needed.

### <a id="add-react-views"></a>Add React Views

Add a view file, `counter.tsx`, to the `src/main/frontend/views` sub-directory. It’ll be accessible under the path, `/counter` in a browser. Here’s an example of how that might look:

counter.tsx

```javascript
import React, { useState } from 'react';
import { Button } from '@vaadin/react-components/Button.js';
import { HorizontalLayout } from '@vaadin/react-components/HorizontalLayout.js';

export default function Counter() {
  const [counter, setCounter] = useState(0);

  return (
    <HorizontalLayout theme="spacing" style={{ alignItems: 'baseline' }}>
      <Button onClick={() => setCounter(counter + 1)}>Button</Button>
      <p>Clicked {counter} times</p>
    </HorizontalLayout>
  );
}
```

The directory, `src/main/frontend/views` is a default location where Vaadin looks for frontend views and configures React Router, based on the file’s structure.

Use [Side Navigation](https://vaadin.com/docs/next/components/side-nav.md) or [Anchor](https://vaadin.com/docs/next/flow/routing/retrieving-routes.md#standard-navigation-targets) components to navigate from a Flow view to a Hilla view:

```java
Anchor navigateToHilla = new Anchor("counter", "Navigate to a Hilla view");
```

### <a id="run-the-application"></a>Run the Application

Run the application using `mvn spring-boot:run`. Then open `http://localhost:8080` in your browser.

Once you add a frontend view, Vaadin starts the Vite development server on the next application run, enabling frontend hot deployment.

## <a id="flow-to-hilla"></a>Add Flow Views to Hilla Applications

If your application already has Hilla views, you can add Vaadin Flow views to it. For example, starting from the Hilla [project starter](https://github.com/vaadin/skeleton-starter-hilla-react)), you can add Flow views to the project using the steps in the sub-sections that follow.

Flow is part of Vaadin, so no dependency adjustment is needed.

### <a id="add-server-side-routes"></a>Add Server-Side Routes

Add a view file, `HelloView.java`, to the `src/main/java/org/vaadin/example/HelloView.java` sub-directory. It’ll be accessible under the path, `/hello` in a browser. Here’s an example of that:

`HelloView.java`

```java
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;

@Route("hello")
public class HelloView extends VerticalLayout {
    public HelloView() {
        TextField textField = new TextField("Your name");
        Button button = new Button("Say hello", e ->
                add(new Paragraph("Hello, " + textField.getValue())));
        add(textField, button);
    }
}
```

Use Vaadin’s [Side Navigation](https://vaadin.com/docs/next/components/side-nav.md) or React’s [NavLink](https://vaadin.com/docs/next/hilla/guides/routing.md#adding-routes) / [Link](https://reactrouter.com/en/main/components/link) components to navigate from a Hilla view to a Flow view:

```javascript
import { NavLink } from 'react-router';

<NavLink to="/flow-route">Navigate to a Flow View</NavLink>
```

### <a id="include-route-to-hilla-main-menu"></a>Include Route to Hilla Main Menu

When using Hilla’s `createMenuItems()` utility function to build the main menu in the main layout, use the `@Menu` annotation to include the server route in the returned menu items. This is described in [Creating Menu from Routes](https://vaadin.com/docs/next/hilla/guides/routing.md#creating-menu-from-routes).

The `@Menu` annotation should always be used together with the `@Route` annotation as in the following example:

`HelloView.java`

```java
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.router.Route;

@Menu
@Route("hello")
public class HelloView extends VerticalLayout {
    public HelloView() {
    }
}
```

The `@Menu` annotation has a `title`, an `order`, and an `icon` attribute. Values are passed to the client side and are available when using the `createMenuItems()` utility function to build the menu.

With access-controlled routes, it’s important not to send any information about them — other than what the user has permission to see. To send a route to the client side, annotate it with `@Menu`. The route must be accessible by [Navigation Access Control](https://vaadin.com/docs/next/flow/security/advanced-topics/navigation-access-control.md).

The value of `MenuAccessControl#getPopulateClientSideMenu` determines the accessibility of the route:

- `AUTOMATIC`: Accessible route is sent to the client. This is the default.

- `ALWAYS`: Always send accessible route.

- `NEVER`: Never send a route.

Only routes sent to the client can be shown in the main menu. In `AUTOMATIC` and `ALWAYS` modes, routes that reach the client are also filtered to include only received server routes if the root main layout exists when using [File Based Routing](https://vaadin.com/docs/next/hilla/guides/routing.md). It checks the existence of the main layout file in `src/main/frontend/views/` (e.g., `src/main/frontend/views/@layout.tsx`).

Mode is configurable with `MenuAccessControl` interface with the `PopulateClientMenu` enumerated list.

The following example changes the default mode to `NEVER` in a Spring Framework application:

`Application.java`

```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.vaadin.flow.server.auth.DefaultMenuAccessControl;
import com.vaadin.flow.server.auth.MenuAccessControl;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public MenuAccessControl customMenuAccessControl() {
        DefaultMenuAccessControl menuAccessControl = new DefaultMenuAccessControl();
        menuAccessControl.setPopulateClientSideMenu(
                MenuAccessControl.PopulateClientMenu.NEVER);
        return menuAccessControl;
    }
}
```

This next example changes the default mode to `NEVER` in a non-Spring application by using [Servlet Initialization Parameters](https://vaadin.com/docs/next/flow/configuration/properties.md#servlet-initialization-parameters) `menu.access.control` with value `org.vaadin.example.CustomMenuAccessControl`. `DefaultMenuAccessControl` implements `MenuAccessControl`:

`org.vaadin.example.CustomMenuAccessControl.java`

```java
import com.vaadin.flow.server.auth.DefaultMenuAccessControl;

public class CustomMenuAccessControl extends DefaultMenuAccessControl {

    public CustomMenuAccessControl() {
        setPopulateClientSideMenu(PopulateClientMenu.NEVER);
    }
}
```

### <a id="flow-page-title-in-hilla-main-menu"></a>Flow Page Title in Hilla Main Menu

As described in [Updating Page Title during Navigation](https://vaadin.com/docs/next/flow/routing/page-titles.md), the page title for a route can be updated with an annotation and with an interface. The page title can be visible anywhere in the Hilla main menu by using Signal: `window.Vaadin.documentTitleSignal`. As long as the signal is initialized on the client side, the server keeps the signal’s value synchronized.

The following example illustrates how to use `window.Vaadin.documentTitleSignal` to show a page title defined with the `PageTitle` annotation in a server-side route in the Hilla main menu. This example includes only the relevant parts that need to be added for the functionality:

@layout.tsx

```javascript
import { createMenuItems, useViewConfig } from '@vaadin/hilla-file-router/runtime.js';
import { effect, Signal, signal } from '@vaadin/hilla-react-signals';

// define Signal<string> type for the window.Vaadin
const vaadin = window.Vaadin as {
    documentTitleSignal: Signal<string>;
};
// initialize signal with empty string
vaadin.documentTitleSignal = signal('');
// keep document title in sync with the signal
effect(() =>  document.title = vaadin.documentTitleSignal.value);

export default function Layout() {
    ...
    // set signal value from the active view config
    vaadin.documentTitleSignal.value = useViewConfig()?.title ?? '';
    ...
    return (
        <AppLayout primarySection="drawer">
            ...
            <h2 slot="navbar" className="text-l m-0">
                {vaadin.documentTitleSignal}
            </h2>
            ...
        </AppLayout>
    );
}
```

## <a id="hilla-server-side-layout"></a>Flow Server Side Layout for Hilla Views

It’s possible to use a Flow server side main layout for both server views and Hilla client views. The server view needs to implement `RouterLayout` and be annotated with `@Layout`.

```java
@Layout
public class MainView extends Div implements RouterLayout {
    // Implementation omitted
}
```

For more information on `RouterLayout`, see [Router Layouts & Nested Router Targets](https://vaadin.com/docs/next/flow/routing/layout.md).

Information on dynamic menu item generation, see [Menu Configuration](https://vaadin.com/docs/next/flow/routing/menu-configuration.md).

> **Note:** If the application is using access protection add `@AnonymousAllowed` on the `MainView` so that the request is not denied.

Hilla views will automatically use the server side layout if a matching one exists, and no Hilla layout is available for the view.

To have a Hilla view ignore the server side layout ViewConfig contains the `flowLayout` value that if set to `false` will ignore automatic server layout.

Sample Client File With Configuration

```javascript
export const config: ViewConfig = {
    flowLayout: false
};

export default function ClientView() {
  return (
    <HorizontalLayout theme="spacing" style={{ alignItems: 'baseline' }}>
      <p>Client layout without server side main layout</p>
    </HorizontalLayout>
  );
}
```

> **Note:** Only one layout type (Hilla react or Flow) is supported at one time.

`9da82521-5074-42b6-82a5-88fc207987d0`
