---
sidebar_position: 3
---
# App Pages and DOM Structure
This page maps the app routes and important DOM areas. It is useful for plugin authors, testers, and contributors who need stable mental models of where UI mounts.
## Angular Routes
| Route | Component | Purpose |
| --- | --- | --- |
| `/` | Redirect | Redirects to `/search`. |
| `/login` | `LoginComponent` | User login. |
| `/register` | `RegisterComponent` | User registration. |
| `/invite/:inviteId` | `InviteComponent` | Resolve and accept invite links. |
| `/search` | `ServerSearchComponent` | Search and join servers. |
| `/room/:roomId` | `ChatRoomComponent` | Main server page with text, voice, members, and plugin panels. |
| `/dm` | `DmWorkspaceComponent` | Direct-message workspace. |
| `/dm/:conversationId` | `DmWorkspaceComponent` | A selected direct-message conversation. |
| `/settings` | `SettingsComponent` | App, voice, server, plugin, desktop, theme, local API settings. |
| `/plugin-store` | `PluginStoreComponent` | Browse plugin sources and install/update plugins. |
| `/plugins/:pluginId/:pageId` | `PluginPageHostComponent` | Host for plugin app pages registered with `api.ui.registerAppPage()`. |
## Page Shell
The renderer is an Angular app. The common shell contains router outlet content plus persistent app surfaces such as the server rail, title bar integrations, settings modals, and floating voice controls.
High-level structure:
```html
```
## Server Page DOM
The server page is the most important page for plugins.
```html
```
## Text Channel Area
Text channel UI is owned by the chat domain.
```html
```
Plugin touchpoints:
- `api.ui.registerComposerAction()` adds composer actions.
- `api.ui.registerEmbedRenderer()` renders declared custom embed payloads.
- `api.ui.mountElement()` can mount into a selector such as `app-chat-messages` when the plugin has `ui.dom`.
## Voice Area
Voice UI is split between channel membership, controls, and media workspace.
```html
```
Plugin touchpoints:
- `api.media.playAudioClip()` plays local audio.
- `api.media.addCustomAudioStream()` contributes audio to voice handling.
- `api.media.addCustomVideoStream()` contributes a video stream.
- `api.channels.addAudioChannel()` creates a voice channel entry when the plugin has channel management rights.
## Plugin Store and Manager DOM
```html
```
Plugin pages registered through `api.ui.registerAppPage()` render at `/plugins/:pluginId/:pageId`:
```html
```
## Plugin Render Host
`PluginRenderHostComponent` accepts plugin render functions that return either an `HTMLElement` or a string. Returning an `HTMLElement` is preferred for interactive UI. Returned strings are rendered as simple text content.
## Stable Selectors for Tests and Plugins
Prefer plugin APIs over DOM selectors. When direct DOM mounting is necessary, use stable app selectors and keep cleanup through the returned disposable.
Common targets:
| Selector | Area |
| --- | --- |
| `body` | Global overlays or modals. |
| `app-chat-messages` | Main text channel surface. |
| `app-rooms-side-panel` | Server side panel. |
| `[data-testid="plugin-room-side-panel"]` | Plugin side-panel area in the server sidebar. |
Avoid depending on Tailwind utility classes; they are layout details and may change.