> Markdown version of [Modifying the bootstrap page](https://vaadin.com/docs/v10/flow/advanced/tutorial-bootstrap). Section index: [llms.txt](https://vaadin.com/docs/v10/flow/llms.txt)

# Modifying the bootstrap page

The application bootstrap page is created for you by the framework and normally there is no need to modify it. For instance Flow includes its internal JavaScripts to be able to provide its core functionality. Also it is possible to include additional JavaScripts, HTML imports and Style Sheets using annotations `@JavaScript`, `HtmlImport` and `@StyleSheet` (see [Including Style Sheets](https://vaadin.com/docs/v10/flow/importing-dependencies/tutorial-include-css.md) and [Importing html/javascript](https://vaadin.com/docs/v10/flow/importing-dependencies/tutorial-importing.md)).

Sometimes you may want to customize the page header and add there some additional data, e.g. custom `meta` tags. Such markup is required to enable your web page to become a rich object in a social graph using [OpenGraph protocol](https://ogp.me/).

## <a id="viewport-annotation"></a>Viewport annotation

Viewport meta-tag can be set to the initial page by annotating the navigation target with `@Route` or the top most `RouterLayout` that builds the navigation target chain.

```java
@Route("")
@Viewport("width=device-width")
public class MyApp extends Div {
  public MyApp() {
    setText("Hello world");
  }
}
```

```java
@Route(value = "", layout = MyLayout.class)
public class MyView extends Div {
  public MyView() {
    setText("Hello world");
  }
}

@Viewport("width=device-width")
public class MyLayout extends Div implements RouterLayout {
}
```

> **Note:** If the ``Viewport annotation is not on a `@Route`` Component or a top `RouterLayout` an exception will be thrown on startup.

## <a id="inline-annotation"></a>Inline annotation

The initial page can be modified by using the `@Inline` annotations to add file contents to either the `<head>` or the `<body>`. Inline is repeatable, so multiple `@Inline` annotations can be added at once.

Inline will add the contents of a classloader resource by default as appended to the head of the initial page with type decided by the file suffix.

The configurations available for inlining contents are:

- TargetElement \[**HEAD**, BODY]

- Position \[**APPEND**, PREPEND]

- Wrapping \[**AUTOMATIC**, NONE, STYLESHEET, JAVASCRIPT]

```java
@Route(value = "", layout = MyInline.class)
public class MyRoot extends Div {
  public MyRoot() {
  }
}

@Inline("initialization.js")
@Inline("initial_style.css")
@Inline(value = "important_styles", wrapping = Inline.Wrapping.STYLESHEET)
public class MyInline extends Div implements RouterLayout {
}
```

> **Note:** If the `Inline` annotation is not on a `@Route` Component or a top `RouterLayout` an exception will be thrown on startup.

## <a id="pageconfigurator"></a>PageConfigurator

To be able to modify default bootstrap page and add your custom meta tags on the page you can implement the `PageConfigurator` on the navigation target with `@Route` or the top most `RouterLayout` that builds the navigation target chain. The `PageConfigurator` gives you easy access to customize the `LoadingIndicatorConfiguration`, `ReconnectDialogConfiguration` and `PushConfiguration` for the initial response.

With the `PageConfigurator` you can prepend or append `javascript`, `html` and `css` to the head by giving a file on the classpath or as content string. Also supported is adding links and meta tags which can also be either prepended or appended.

Setting the viewport meta tag using `InitialPageSettings::setViewport` will override any viewport set through a `@Viewport` annotation.

By default everything is appended, but if needed you can give the position `InitialPageSettings.Position.PREPEND` to have the item prepended to head instead.

Here is the code for the `PageConfigurator` implementation on the top `RouterLayout` which modifies the header of the page:

```java
@Route(value = "", layout = MainLayout.class)
public class Root extends Div {
}

public class MainLayout extends Div
        implements RouterLayout, PageConfigurator {

    @Override
    public void configurePage(InitialPageSettings settings) {
        settings.addInlineFromFile(InitialPageSettings.Position.PREPEND,
                "inline.js", InitialPageSettings.WrapMode.JAVASCRIPT);

        settings.addMetaTag("og:title", "The Rock");
        settings.addMetaTag("og:type", "video.movie");
        settings.addMetaTag("og:url",
                "https://www.imdb.com/title/tt0117500/");
        settings.addMetaTag("og:image",
                "https://ia.media-imdb.com/images/rock.jpg");

        settings.addLink("shortcut icon", "icons/favicon.ico");
        settings.addFavIcon("icon", "icons/icon-192.png", "192x192");
    }
}
```

> **Note:** If the PageConfigurator implementation is not on a `@Route` Component or a `RouterLayout` used from a route it will not be used.

## <a id="setting-the-body-size-styles"></a>Setting the body size styles

By default, the body element in a Flow application has size properties `height = "100vh", width = "100vw"`, which makes the page fill the entire viewport. To change the width and height properties of the body you can either use the `@BodySize` annotation or the `PageConfigurator`.

For `@BodySize` you just add it to the the navigation target with `@Route` or the top most `RouterLayout` that builds the navigation target chain. You can pass custom height and width properties for the annotation, or leave them out to just prevent the default size to be applied for the body:

```java
@Route("")
@BodySize
public static class BodySizeAnnotatedRoute extends Div {
}
```

With the `PageConfigurator` you can just addInlineContent like:

```java
@Route("")
public static class InitialPageConfiguratorBodyStyle extends Div
        implements PageConfigurator {
    @Override
    public void configurePage(InitialPageSettings settings) {
        settings.addInlineWithContents("body {width: 100vw; height:100vh;}",
                InitialPageSettings.WrapMode.STYLESHEET);
    }
}
```

> **Note:** Only one way should be used as else the later statement will override the earlier one. In practise this would mean that by default the `PageConfigurator` will override the `@BodySize` except if the inlining is done as a `PREPEND` then the `@BodySize` will be the deciding one.

> **Note:** If the `BodySize` annotation is not on a `@Route` Component or a top `RouterLayout` an exception will be thrown on startup.

> **Note:** When using an empty `@BodySize` annotation (which doesn’t apply any sizing for the UI / body), you will not be able to use relative sizing (% as unit) for any component, unless the component has a parent that has defined size using anything else than % as the unit. For that reason, it is recommended to use the default settings for the body size, by omitting the `@BodySize` annotation, or to declare a specific size for it.

## <a id="bootstraplistener"></a>BootstrapListener

To be able to modify default bootstrap page and add your custom meta tags on the page you should use your `BootstrapListener` implementation and add it to the `ServiceInitEvent` instance available in a `VaadinServiceInitListener`.

Here is the code for the `BoostrapListener` implementation which modifies the header of the page:

```java
public class CustomBootstrapListener implements BootstrapListener {

    public void modifyBootstrapPage(BootstrapPageResponse response) {
        Document document = response.getDocument();

        Element head = document.head();

        head.appendChild(createMeta(document, "og:title", "The Rock"));
        head.appendChild(createMeta(document, "og:type", "video.movie"));
        head.appendChild(createMeta(document, "og:url",
                "https://www.imdb.com/title/tt0117500/"));
        head.appendChild(createMeta(document, "og:image",
                "https://ia.media-imdb.com/images/rock.jpg"));
    }

    private Element createMeta(Document document, String property,
            String content) {
        Element meta = document.createElement("meta");
        meta.attr("property", property);
        meta.attr("content", content);
        return meta;
    }
}
```

Now this listener should be added to a `ServiceInitEvent` which is sent when a Vaadin service is initialized. Take a look on the [ServiceInitListener tutorial](https://vaadin.com/docs/v10/flow/advanced/tutorial-service-init-listener.md) on how to configure it.

## <a id="adding-static-html-contents"></a>Adding static HTML contents

The framework provides multiple ways of adding static content to the page. Here we cover three different ways of adding a favicon.

- using `InitialPageSettings#addLink()`

```java
public class Layout1 extends Div implements RouterLayout, PageConfigurator {

    @Override
    public void configurePage(InitialPageSettings settings) {
        HashMap<String, String> attributes = new HashMap<>();
        attributes.put("rel", "shortcut icon");
        settings.addLink("icons/favicon.ico", attributes);
    }
}
```

- using `InitialPageSettings#addInlineWithContents()`

```java
public class Layout2 extends Div implements RouterLayout, PageConfigurator {

    @Override
    public void configurePage(InitialPageSettings settings) {
        settings.addInlineWithContents(
                "<link rel=\"shortcut icon\" href=\"icons/favicon.ico\">",
                InitialPageSettings.WrapMode.NONE);
    }
}
```

- using `BootstrapListener#modifyBootstrapPage()` ([documentation](https://vaadin.com/docs/v10/flow/advanced/tutorial-bootstrap.md#bootstraplistener))

```java
public class Layout3 extends Div
            implements RouterLayout, BootstrapListener {

        @Override
        public void modifyBootstrapPage(BootstrapPageResponse response) {
            final Element head = response.getDocument().head();
            head.append(
                    "<link rel=\"shortcut icon\" href=\"icons/favicon.ico\">");
        }
    }
```

But most commonly, you will deal with quite many files, in this case, you can see that it causes a lot of hard coding easily. To avoid this, we recommend you to move all the contents into a file, (e.g. `your-content.html`) and inline this file in your `PageConfigurator`

```java
public class Layout4 extends Div implements RouterLayout, PageConfigurator {

        @Override
        public void configurePage(InitialPageSettings settings) {
            settings.addInlineFromFile("your-content.html",
                    InitialPageSettings.WrapMode.NONE);
        }
    }
```
