# Code tabs on previews
> Replace a preview's Code panel with tabs you write, switch them together across the site, and add a page-level switch and a caption.
Source: https://shelldocs.shellui.dev/docs/components/code-tabs
A preview's Code panel normally shows the Razor that rendered it. Put `` children inside the preview and the panel shows those instead, one tab each. Use it when the reader's code isn't the code that drew the example : the same result in two syntaxes, or one live example documented for several platforms.
**Markdown**
```markdown
```
**Razor**
```razor
@foreach (var package in Packages)
{
}
```
Written as:
````markdown
```markdown
```
```razor
@foreach (var package in Packages)
{
}
```
````
## The rules
- Each tab's code is the first fence inside it. The fence's language drives highlighting.
- Without a fence, the tag's text is the code and `Language="â¦"` sets the language.
- The **Copy** button copies the tab that is showing.
- Without `` children the Code panel shows the Razor source, as before.
## Where they work
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `DemoPreview` | `yes` | | The tabs replace the demo's .razor file in the Code panel. |
| `ComponentPreview` | `yes` | | The tabs are taken out of the body before it is passed to the component as child content. |
| `IframePreview` | `yes` | | Without tabs an iframe preview has no Code panel at all. |
| `razor:preview fence` | `no` | | The fence body is Razor, so a code fence can't sit inside it. Use DemoPreview instead. |
## Switching together
`SyncKey` works as it does on [`CodeGroup`](https://shelldocs.shellui.dev/docs/components/code-group.md) and [`Tabs`](https://shelldocs.shellui.dev/docs/components/tabs.md). Every block with the same key switches together, on this page and on later ones, and the choice is saved in `localStorage`.
## A missing tab
When a block has no tab for the current choice it says so and keeps its height, instead of jumping to another tab. Choose **Razor** in the first example, then look at this one:
**Markdown**
```markdown
```
## Page switch
A page switch is a row of tabs on the page itself that drives a `SyncKey`. The **Markdown | Razor** row at the top of this page is one. Declare it once and it appears on every page whose blocks use that key:
```csharp
builder.Services.AddShellDocs(o =>
{
o.AddSyncSwitch("platform", "MAUI", "Avalonia");
});
```
It sits under the page header when `RenderPageTitle` is on, otherwise right above the first block that uses the key. Pages that don't use the key don't get one. The first option is the default until a reader picks another, so every block starts on the same tab.
To choose the spot yourself, write the tag. The automatic one is then left out on that page:
```markdown
```
For a key with no `AddSyncSwitch`, list the options on the tag. This page does that:
```markdown
```
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `SyncKey` (required) | `string` | `â` | The key the switch drives. |
| `Options` | `string?` | `from AddSyncSwitch` | Comma-separated option labels. They must match the tab labels. |
## Caption
`Caption` adds a short muted note to the preview's toolbar, such as which platform rendered the example. The first preview on this page has one.
```markdown
```
`ShellDocsOptions.PreviewCaption` sets a caption for every preview on the site. A preview's own `Caption` replaces it.
```csharp
o.PreviewCaption = "Rendered with Blazor";
```
## From a Razor file
Outside markdown, pass the tabs as a parameter:
```razor
```
A `PreviewCodeTab` is a label, the code, and a language that defaults to `text`.
## XAML
`xaml` and `axaml` fences are highlighted as XML. Sites created before `0.1.13-alpha` need `'xml'` in the `langs` list of the Shiki loader in `App.razor`.
## Props
These are the same on `DemoPreview`, `ComponentPreview` and `IframePreview`.
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `SyncKey` | `string?` | `â` | Blocks with the same key switch together and remember the choice. |
| `Caption` | `string?` | `PreviewCaption` | Muted note in the toolbar. |
| `CodeTabs` | `IReadOnlyList?` | `â` | The tabs, when the preview is written in a .razor file. |
`CodeTab` inside a preview:
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `Label` (required) | `string` | `â` | Tab label, and the value a SyncKey matches on. |
| `Language` | `string?` | `text` | Highlighting language when the body has no fence. |
## See also
- [DemoPreview](https://shelldocs.shellui.dev/docs/components/demo-preview.md): The preview these tabs most often sit in.
- [IframePreview](https://shelldocs.shellui.dev/docs/components/iframe-preview.md): A live example from another page, with the same tabs.