# Overlay View Components


Overlay views are built using a declarative XML syntax. Each XML element maps to an HTML element that Meta renders inside a secure iframe. You compose these elements to display player information — names, profile pictures, scores — that your game cannot access directly under the Zero Permissions model.

This page documents every available component, its attributes, and how to use it effectively.

> **Unity developers:** You can create overlay views using the C# API (`FBInstant.OverlayViews.CreateOverlayViewAsync`) or the visual Overlay View Builder editor tool. See the [Unity Plugin](https://developers.facebook.com/documentation/games/sdk-reference/unity-plugin) for details.

## How Components Work

When you create an overlay view using `FBInstant.overlayViews.createOverlayViewAsync()`, the platform parses your XML, resolves any template expressions (such as `{{FBInstant.player.name}}`), and renders the result as HTML inside an iframe. Your game controls the iframe's position and size, but Meta controls the content inside it.

Components fall into two categories:

- **Basic components** render visible elements — containers, text, buttons, and images.
- **Control structure components** handle logic — loops, conditionals, and compound conditions.

## Basic Components

### View

A generic container element. Renders as a `<div></div>` in the final HTML. Use `View` to group other components, apply layout styles, and handle tap events.

| Attribute | Type | Description |
|-----------|------|-------------|
| `className` | String | CSS class name defined in your `styles.css` file (included in your game bundle). |
| `style` | String | Inline CSS styles applied directly to the element. Use CSS property syntax with semicolons (e.g., `"display: flex; gap: 8px"`). |
| `onTapEvent` | String | A custom event name that fires when the user taps or clicks this element. The event is delivered to your game via `FBInstant.overlayViews.setCustomEventHandler()`. |

```xml
<View className="card" style="display: flex; align-items: center; gap: 12px"
      onTapEvent="selectPlayer_{{playerID}}">
  <!-- Child components go here -->
</View>
```

### Text

Renders a paragraph of text. Renders as a `<p></p>` element in the final HTML.

| Attribute | Type | Description |
|-----------|------|-------------|
| `className` | String | CSS class name for styling. |
| `style` | String | Inline CSS styles. |
| `content` | String | The text to display. Supports template expressions like `{{FBInstant.player.name}}` or `{{myVariable}}`. |

```xml
<Text content="Welcome, {{FBInstant.player.name}}!" className="greeting" />
```

### Button

An interactive button element. Renders as a `<button></button>` in the final HTML. Buttons can either fire a custom event (via `onTapEvent` on a parent `View`) or trigger a built-in context action.

| Attribute | Type | Description |
|-----------|------|-------------|
| `className` | String | CSS class name for styling. |
| `style` | String | Inline CSS styles. |
| `content` | String | The button's display text. Supports template expressions. |
| `action` | String | A context action to execute when pressed. Use `{{FBInstant.action.contextCreate(playerId)}}` or `{{FBInstant.action.switchContext(contextId)}}` to trigger context changes directly from the overlay. |

```xml
<Button content="Challenge" action="{{FBInstant.action.contextCreate({{friend.id}})}}"
        className="challengeBtn" />
```

### Image

Displays an image. Renders as an `<img>` element in the final HTML.

| Attribute | Type | Description |
|-----------|------|-------------|
| `className` | String | CSS class name for styling. |
| `style` | String | Inline CSS styles. |
| `src` | String | The image source (see allowed sources below). |
| `width` | Number | Image width in pixels (e.g., `width="48"`). |
| `onTapEvent` | String | A custom event name that fires when the image is tapped. |

```xml
<Image src="{{FBInstant.player.photo}}" className="avatar" width="48" style="border-radius: 50%" />
```

> **Note:** When a player opts for their actual profile image (rather than a gaming avatar), the image is 128x128 pixels.

#### Allowed Image Sources

Overlay views can only load images from specific sources. External CDN URLs (Cloudflare, AWS, etc.) are **not supported**.

| Source | Example | Works? |
|--------|---------|:------:|
| Game bundle (relative path) | `src="icons/sword.png"` | Yes |
| Player photo template | `src="{{FBInstant.player.photo}}"` | Yes |
| Arbitrary player photo | `src="{{FBInstant.players[{{id}}].photo}}"` | Yes |
| Base64 data URL (via `initialData`) | `src="{{iconBase64}}"` | Yes |
| External CDN URL | `src="https://cdn.example.com/img.png"` | **No** |

If you need to display images from your CDN, fetch them in your game's JavaScript, convert to base64, and pass them via `initialData`:

```javascript
// In your game code
async function toBase64(url) {
  var res = await fetch(url);
  var blob = await res.blob();
  return new Promise(function(resolve) {
    var reader = new FileReader();
    reader.onloadend = function() { resolve(reader.result); };
    reader.readAsDataURL(blob);
  });
}

var icon = await toBase64('https://your-cdn.com/icon.png');

var overlay = await FBInstant.overlayViews.createOverlayViewAsync(
  'overlays/inventory.xml', container, iframeStyle, null, { iconBase64: icon }
);
```

```xml
<Image src="{{iconBase64}}" width="32" />
```

## Control Structure Components

Control structures let you add logic to your overlay views — iterating over lists of players, conditionally showing content, and combining conditions.

### For

Iterates over a data source and renders its child components once for each item. This is how you build lists of players, leaderboard entries, or any repeated UI pattern.

| Attribute | Type | Required | Description |
|-----------|------|----------|-------------|
| `source` | String | Yes | The data to iterate over. Can be a built-in source like `{{FBInstant.player.connectedPlayers}}` or `{{FBInstant.context.participants}}`, or a custom list passed via `initialData`. |
| `itemName` | String | Yes | The variable name used to reference each item inside the loop body (e.g., `"player"`). Access item properties with `{{player.name}}`, `{{player.photo}}`, etc. |
| `sortKey` | String | No | A property name to sort items by. Can reference player data keys or custom data. |
| `order` | String | No | Sort direction: `ASC` (ascending) or `DESC` (descending). Defaults to `ASC`. |
| `limit` | Number | No | Maximum number of items to render. |
| `startIndex` | Number | No | The starting index for iteration. Defaults to `1`. |
| `scrollStyle` | String | No | Controls overflow scroll position when the list exceeds the visible area. Values: `top`, `bottom`, `center`. |
| `scrollIndex` | Number | No | When `scrollStyle` is `center`, specifies which item index to center the scroll on. |

```xml
<View>
  <For source="{{FBInstant.player.connectedPlayers}}" itemName="friend"
       sortKey="name" order="ASC" limit="10">
    <View className="friendRow" style="display: flex; align-items: center; gap: 8px">
      <Image src="{{friend.photo}}" style="width: 40px; height: 40px; border-radius: 50%" />
      <Text content="{{friend.name}}" className="friendName" />
    </View>
  </For>
</View>
```

You can also sort by dynamic keys using nested template expressions. This is useful when you have score data keyed by player ID:

```xml
<For source="{{players}}" itemName="player"
     sortKey="{{scores[{{player.id}}]}}" order="DESC">
  <View>
    <Text content="{{player.name}}" />
    <Text content="Score: {{scores[{{player.id}}]}}" />
  </View>
</For>
```

### If, ElseIf, and Else

Conditional rendering blocks. Use `If` to show content only when a condition is met, with optional `ElseIf` and `Else` branches for fallback content.

```xml
<If>
  <Condition lhs="{{playerScore}}" operator="GREATER_THAN" rhs="1000" />
  <View>
    <Text content="High scorer!" className="badge" />
  </View>
  <ElseIf>
    <Condition lhs="{{playerScore}}" operator="GREATER_THAN" rhs="500" />
    <View>
      <Text content="Getting there!" />
    </View>
  </ElseIf>
  <Else>
    <View>
      <Text content="Keep playing!" />
    </View>
  </Else>
</If>
```

### Condition

Defines a comparison inside an `If` or `ElseIf` block.

| Attribute | Type | Description |
|-----------|------|-------------|
| `lhs` | String | The left-hand side value. Supports template expressions. |
| `operator` | String | The comparison operator (see table below). |
| `rhs` | String | The right-hand side value. Supports template expressions. |

**Available operators:**

| Operator | Meaning |
|----------|---------|
| `EQUALS` | `lhs == rhs` |
| `NOT_EQUALS` | `lhs != rhs` |
| `GREATER_THAN` | `lhs > rhs` |
| `NOT_GREATER_THAN` | `lhs <= rhs` |
| `LESS_THAN` | `lhs < rhs` |
| `NOT_LESS_THAN` | `lhs >= rhs` |
| `IN` | `lhs` is contained in `rhs` (array or string) |
| `NOT_IN` | `lhs` is not contained in `rhs` |

### ConditionGroup

Combines multiple `Condition` elements under a logical operator. Use this when you need to evaluate more than one condition together.

| Attribute | Type | Description |
|-----------|------|-------------|
| `operator` | String | `AND` (all conditions must be true) or `OR` (at least one must be true). |

```xml
<If>
  <ConditionGroup operator="AND">
    <Condition lhs="{{level}}" operator="GREATER_THAN" rhs="5" />
    <Condition lhs="{{hasKey}}" operator="EQUALS" rhs="true" />
  </ConditionGroup>
  <View>
    <Text content="Secret area unlocked!" />
  </View>
</If>
```

## Styling Best Practices

Overlay views support CSS styling through both inline `style` attributes and external CSS files referenced when creating the overlay.

**Recommended approach:**

1. Define reusable styles in a `styles.css` file in your game bundle.
2. Reference classes via the `className` attribute on components.
3. Use inline `style` for one-off positioning or dynamic values.

```css
/* styles.css */
.friendRow {
  display: flex;
  align-items: center;
  padding: 8px;
  border-bottom: 1px solid #eee;
}

.avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
}
```

> **Known issue:** `position: absolute` can cause rendering issues in overlay views. Use `position: relative` with flexbox layouts as a workaround.

### Custom Fonts

Custom fonts must be defined using `@font-face` in an external CSS file — you cannot add `<style>` blocks inside XML. Only **TTF** font files are supported.

```css
/* styles.css */
@font-face {
  font-family: 'MyGameFont';
  src: url('MyGameFont.ttf');
}

.game-text {
  font-family: 'MyGameFont';
  font-size: 18px;
}
```

Include the font file in your game bundle alongside the CSS file. The font is loaded before the overlay renders, so there is no flash of unstyled text.

### Overlay Reuse

Overlays are not garbage collected when dismissed — `dismissAsync()` only hides the iframe. To avoid unnecessary memory usage:

- **Reuse overlays** by calling `updateAsync()` + `showAsync()` instead of creating new ones.
- **Pre-create a pool** for variable-count overlays (e.g., per-player name tags) at startup and recycle them.
- **Keep frequently updated overlays small.** Every `updateAsync()` call triggers a full re-render, including re-fetching all images.

## Next Steps

- **[Example Game Use Cases](https://developers.facebook.com/documentation/games/build/zero-permissions/example-game-use-cases)** — See complete examples of overlay views for friend lists, leaderboards, and more.
- **[Overlay Preview Tool](https://developers.facebook.com/documentation/games/build/zero-permissions/overlay-preview-tool)** — Build and test overlay views interactively in the browser.
- **[API Reference](https://developers.facebook.com/documentation/games/build/zero-permissions/api-reference)** — Full reference for the `FBInstant.overlayViews` module.