Skip to content

Tabs ​

Tabs are a top-level navigation pattern: a tab bar of buttons at the bottom (or top) of the screen switches between independent root pages.

IonTabs is the container: a content area plus Top and Bottom slots for the bar. IonTabBar is the bar, and each IonTabButton in it navigates to a route. There is no ion-tab component and no tab outlet: each tab is its own routed page, and the tabs container lives in the app layout so it stays on screen while the pages change.

Tab layout ​

Put IonTabs in the default layout inside IonApp, with @Body in the Content slot and the IonTabBar in Bottom (or Top). The slot decides where the bar goes; IonTabBar's Slot parameter only picks the border side. A tap on a button performs a root navigation to its Href: the history is cleared, no transition plays, and each tab page's scroll position is restored when you switch back to it. OnClick runs before the navigation.

Selected is not derived from the route — set it yourself, typically by comparing the layout's NavigationManager.CurrentPath with each tab's path (as the tabs app template does). Navigation re-renders the layout, so Selected follows the current page. A button is identified by its Href; Ionic's tab attribute, which names an ion-tab, has no counterpart.

razor
@inherits LayoutComponentBase

@* MainLayout.razor of the tabs template. The routed page goes in Content; the tab bar in
   Bottom. Selected is not automatic: compare each tab with the current path. *@
<IonApp>
    <IonTabs>
        <Content>@Body</Content>
        <Bottom>
            <IonTabBar Slot="bottom">
                <IonTabButton Href="/tab1" Selected="@IsActive("/tab1", "/")">
                    <IonIcon Icon="@Ionicons.Triangle" />
                    <IonLabel>Tab 1</IonLabel>
                </IonTabButton>
                <IonTabButton Href="/tab2" Selected="@IsActive("/tab2")">
                    <IonIcon Icon="@Ionicons.Ellipse" />
                    <IonLabel>Tab 2</IonLabel>
                </IonTabButton>
                <IonTabButton Href="/tab3" Selected="@IsActive("/tab3")">
                    <IonIcon Icon="@Ionicons.Square" />
                    <IonLabel>Tab 3</IonLabel>
                </IonTabButton>
            </IonTabBar>
        </Bottom>
    </IonTabs>
</IonApp>

@code {
    private string CurrentPath => NavigationManager?.CurrentPath ?? "/";

    private bool IsActive(params string[] paths) =>
        paths.Any(p => string.Equals(p, CurrentPath, StringComparison.OrdinalIgnoreCase));
}

Tab pages ​

A tab page is an ordinary routed page with its own IonPage, header, and content; it fills the area above the tab bar. Give the first tab the "/" route as well, so the app starts on it — and include "/" in that tab's Selected check.

razor
@* Pages/Tab1Page.razor — the real file starts with @page "/" and @page "/tab1". A tab page is
   an ordinary page; the layout supplies the tab bar. *@
<IonPage>
    <IonHeader>
        <IonToolbar>
            <IonTitle>Tab 1</IonTitle>
        </IonToolbar>
    </IonHeader>
    <IonContent>
        <div class="ion-padding">
            <p>This is the first tab page.</p>
        </div>
    </IonContent>
</IonPage>

A page pushed from a tab (for example through an IonItem Href) renders in the same content area, so the tab bar stays visible. Unlike Ionic there is a single history stack, not one per tab: a pushed page can go back to its tab page, but a tab switch clears the stack, so the back button cannot undo it and the pushed page is not remembered when you return to that tab.

Badges ​

An IonBadge inside a tab button floats over the top-right corner of the icon instead of flowing under the label. An empty badge is drawn as an 8px dot in md mode and stays hidden in ios mode.

razor
@* A badge floats over the top-right of the icon. An empty badge is an 8px dot in md mode and
   hidden in ios mode. *@
<IonTabBar>
    <IonTabButton Href="/inbox" Selected="true">
        <IonIcon Icon="@Ionicons.MailOutline" />
        <IonLabel>Inbox</IonLabel>
        <IonBadge Color="danger">3</IonBadge>
    </IonTabButton>
    <IonTabButton Href="/calendar">
        <IonIcon Icon="@Ionicons.Calendar" />
        <IonLabel>Calendar</IonLabel>
        <IonBadge Color="primary"></IonBadge>
    </IonTabButton>
</IonTabBar>

Top tab bar ​

Put the bar in the Top slot to place it above the content; Slot="top" on the bar moves its border to the bottom edge and pads it for the top safe-area inset instead of the bottom one.

razor
@* The IonTabs slot decides the position; Slot="top" only moves the border to the bottom edge. *@
<IonTabs>
    <Top>
        <IonTabBar Slot="top">
            <IonTabButton Href="/music" Selected="true">
                <IonLabel>Music</IonLabel>
            </IonTabButton>
            <IonTabButton Href="/movies">
                <IonLabel>Movies</IonLabel>
            </IonTabButton>
        </IonTabBar>
    </Top>
    <Content>
        <IonPage>
            <IonContent>
                <div class="ion-padding">
                    <p>Music</p>
                </div>
            </IonContent>
        </IonPage>
    </Content>
</IonTabs>

Requirements ​

  • An IonTabButton navigates only inside an IonTabs (it receives the container as a cascading value). Outside it — for example in an IonTabBar that is not in an IonTabs slot — it only raises OnClick.
  • Href must be a route the app defines; without Href a tap does not navigate.
  • A tab bar in a layout is built once per navigation, so Selected must be computed from the current path rather than from a field set in OnClick.

API ​

Every component also accepts Class (extra CSS classes), Style (an inline Style object) and Id (the root element's id) — see Conventions.

IonTabs ​

SlotTypeDescription
BottomRenderFragment?Content rendered after the main tabs area, corresponding to Ionic's slot="bottom".
ContentRenderFragment?The routed page content (in a tabs layout, @Body), rendered in the growing tabs-inner area between the Top and Bottom slots.
TopRenderFragment?Content rendered before the main tabs area, corresponding to Ionic's slot="top".

IonTabBar ​

ParameterTypeDefaultDescription
Slotstring"bottom"Ionic's slot attribute on ion-tab-bar: "bottom" (default) or "top", stamped as ion-tab-bar-bottom / ion-tab-bar-top. It picks the border side and the safe-area inset the bar pads for (a bottom bar: top border, bottom inset; a top bar: bottom border, top inset); the IonTabs slot the bar is placed in (Bottom / Top) decides the position.
SlotTypeDescription
ChildContentRenderFragment?Content placed between the component's tags.

IonTabButton ​

ParameterTypeDefaultDescription
Hrefstring?nullNavigation target for the tab button. When the button sits inside an IonTabs, clicking it performs a root-level navigation to this target (history cleared, no page transition), mirroring Ionic's tab switching. Outside an IonTabs the button does not navigate.
SelectedboolfalseWhether this tab button is the currently selected one (stamps tab-selected). Not derived from the route — the app sets it, e.g. by comparing NavigationManager.CurrentPath with Href.
EventTypeDescription
OnClickEventCallbackInvoked when the tab button is clicked.
SlotTypeDescription
ChildContentRenderFragment?Content placed between the component's tags.

Styling ​

Theme tokens ​

Bar… values style IonTabBar; Button… values style IonTabButton and the badge inside it. ButtonIconSize sizes an IonIcon inside a tab button, and an IonLabel there takes the button's font size.

Theme token IonicTheme.Tab (TabToken). Assign only the values you want to change — the rest keep the mode defaults below. App-wide: builder.AddIonic(o => o.Theme.Tab = new TabToken { … }); for one subtree: a ConfigProvider. See Theming.

TokenTypemdios
BarBackgroundColor#ffffff#f7f7f7
BarBorderColorColorrgba(0, 0, 0, 0.07)rgba(0, 0, 0, 0.2)
BarBorderWidthfloat11
BarColorColor#595959#737373
BarColorSelectedColor#0054e9#0054e9
BarHeightfloat5650
ButtonBadgeBorderRadiusfloat810
ButtonBadgeFontSizefloat812
ButtonBadgeMinWidthfloat1210
ButtonBadgePaddingBottomfloat21
ButtonBadgePaddingEndfloat26
ButtonBadgePaddingStartfloat26
ButtonBadgePaddingTopfloat31
ButtonBadgeSizeEmptyfloat88
ButtonFontSizefloat1210
ButtonIconSizefloat2224
ButtonMaxWidthfloat168240
ButtonPaddingXfloat122

CSS classes ​

App stylesheet rules always win over Ionic's own rules (see Theming), so these classes can be targeted directly from GlobalStyles.cs.

SelectorElement
.ion-tabsThe IonTabs host: a flex column filling its parent. Also carries the mode (md / ios).
.ion-tabs .tabs-innerThe content area (Content slot), which grows to push the bar to the edge.
.ion-tab-barThe bar: height, background, color, safe-area padding.
.ion-tab-bar-bottom, .ion-tab-bar-topIonTabBar.Slot: border on the top or bottom edge.
.ion-tab-buttonA tab button: icon stacked above the label.
.ion-tab-button.tab-selectedThe selected button (selected color).
.ion-tab-button .ion-badgeA badge in a tab button.
csharp
// GlobalStyles.cs — bold label on the selected tab.
[".ion-tab-button.tab-selected .ion-label"] = new() { FontWeight = FontWeight.Bold },

Released under the MIT License.