# 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.