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