
Tabs
A collection of data that is associated with the separation content but belongs to a different category.
Tab components are designed in the form of templates, and this component is used by adding TabItem
subcomponents to the tabItems
in the template
Set additional information during tab navigation
- InfoItem1
- Tab properties can be set when navigating using the built-in extension method
Navigator.NavigateTo("url", "text", "icon", "closable")
- InfoItem3
- Setting
@attribute [TabItemOption(Text = "LayoutPage", Icon = "fa fa-fa")]
inrazor
page
Basic, concise tabs.
Demo
Set tab-style tabs by isCard='true'
.
Demo
Set tab-style tabs by IsBorderCard='true'
.
Demo
Set the tab icon by setting the Icon
property of the TabItem
component
Demo
Show the close button to the tab by setting the ShowClose
property
Demo
By setting the Placement
property to change the label position, a small arrow scrolls up and down to TabItem
switch when you change to left or right
Demo
Dynamically add/remove TabItem
by calling the component api
Demo
other components are built into the TabItem
Demo
Tab
The contents of each panel of the component remain state by default, and in this case the original data is maintained when the panel switches
Counter
Current count: 0
Weather forecast
This component demonstrates fetching data from a service.
Date | Temp. (C) | Temp. (F) | Summary |
---|---|---|---|
8/14/2022 | 43 | 109 | Cool |
8/15/2022 | -5 | 24 | Mild |
8/16/2022 | 18 | 64 | Scorching |
8/17/2022 | 17 | 62 | Balmy |
8/18/2022 | 1 | 33 | Chilly |
This feature allows you to click on the menu link in the sidebar and render multiple labels at the top of the data area on the right
Demo
In this example, the right the Tab
the inside of the panel remains in state, and the component reloads when it is closed and reopened
By setting the ShowExtendButtons
property to true
, turning on the left and right buttons of the component and closing the drop-down menu, it is very useful in practice
Demo
By setting the isOnlyRenderActiveTab
parameter, the component renders only the current active label
Demo
Counter
Current count: 0
customer the header UI via HeaderTemplate
Demo
Badge
in the HeaderTemplate
Counter
Current count: 0
Attributes
Method
@page "/tabs"
@inject IStringLocalizer<Tabs> Localizer
<h3>Tabs</h3>
<h4>A collection of data that is associated with the separation content but belongs to a different category.</h4>
<p>Tab components are designed in the form of templates, and this component is used by adding <code>TabItem</code> subcomponents to the <code>tabItems</code> in the template</p>
<Tips>
<p>
<code>Tab</code> components are generally used in two ways:
<ul class="ul-demo mb-3">
<li>Split as data</li>
<li>Page navigation</li>
</ul>
<div>The default behavior of this component is data segmentation,Clicking on the <code>TabItem</code> title does not navigate, and if you need to navigate the address bar, set the <code>ClickTabToNavigation</code> property to <code>true</code>,When you click on the <code>TabItem</code> title, the address bar redirects navigation, mostly for the background management system to be used in conjunction with the <code>Menu</code> components,The actual combat can refer to the <code>multi-label</code> mode in the <a href='layout-page' target='_blank'>background template simulator</a>, When you have <code>Razor Component</code> in the additional Assemblies, set the <code>AdditionalAssemblies</code> property value correctly so that the route within the label component is resolved correctly, and the relevant documentation <a href='https://docs.microsoft.com/zh-cn/aspnet/core/blazor/fundamentals/routing?WT.mc_id-DT-MVP-5004174-view-aspnetcore-3.1-route-to-components-from-multiple-assemblies' target'_blank'>[Portal]</a></div>
</p>
<p>This component adapts to width height, etc., and scroll arrows can appear left and right or up and down when appropriate</p>
</Tips>
<p>
<b>Set additional information during tab navigation</b>
</p>
<ul class="ul-demo">
<li>@((MarkupString)Localizer["InfoItem1"].Value)</li>
<li>Tab properties can be set when navigating using the built-in extension method <code>Navigator.NavigateTo("url", "text", "icon", "closable")</code></li>
<li>@((MarkupString)Localizer["InfoItem3"].Value)</li>
<li>Setting <code>@attribute [TabItemOption(Text = "LayoutPage", Icon = "fa fa-fa")]</code> in <code>razor</code> page</li>
</ul>
<DemoBlock Title="Basic usage" Introduction="Basic, concise tabs." Name="Normal">
<Tab>
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department ">
<div>I am department management</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Tab style " Introduction="Set tab-style tabs by <code>isCard='true'</code>." Name="Card">
<Tab IsCard="true">
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department ">
<div>I am department management</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Carding" Introduction="Set tab-style tabs by <code>IsBorderCard='true'</code>." Name="Border">
<Tab IsBorderCard="true">
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department ">
<div>I am department management</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Icon" Introduction="Set the tab icon by setting the <code>Icon</code> property of the <code>TabItem</code> component" Name="Icon">
<Tab IsCard="true">
<TabItem Text="User" Icon="fa fa-user">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu" Icon="fa fa-dashboard">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles" Icon="fa fa-sitemap">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department " Icon="fa fa-bank">
<div>I am department management</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Close" Introduction="Show the close button to the tab by setting the <code>ShowClose</code> property" Name="Closable">
<Tips>
<p><code>Tab</code> component turns on the <code>showClose</code> , <code>TabItem</code> property <code>Closable</code> can be set individually to close tab, <b>defaulting to </b><code>true</code>;In this example <b>User</b>Tabs do not provide a to turn off functionality</p>
</Tips>
<Tab IsCard="true" ShowClose="true">
<TabItem Text="User" Icon="fa fa-user" Closable="false">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu" Icon="fa fa-dashboard">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles" Icon="fa fa-sitemap">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department " Icon="fa fa-bank">
<div>I am department management</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Position" Introduction="By setting the <code>Placement</code> property to change the label position, a small arrow scrolls up and down to <code>TabItem</code> switch when you change to left or right" Name="Placement">
<p class="text-center">
<div class="btn-group">
<button class="btn btn-primary" @onclick="e => SetPlacement(Placement.Top)">Top</button>
<button class="btn btn-primary" @onclick="e => SetPlacement(Placement.Right)">Right</button>
<button class="btn btn-primary" @onclick="e => SetPlacement(Placement.Bottom)">Bottom</button>
<button class="btn btn-primary" @onclick="e => SetPlacement(Placement.Left)">Left</button>
</div>
</p>
<Tab Placement="@BindPlacement" Height="200">
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="System logs">
<div>I am a system log</div>
</TabItem>
<TabItem Text="Sign log">
<div>I am Sign log management</div>
</TabItem>
<TabItem Text="Timed task">
<div>I am a timed task manager</div>
</TabItem>
</Tab>
<Divider Text="Split Line"></Divider>
<Tab Placement="@BindPlacement" IsCard="true" Height="200">
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="System logs">
<div>I am a system log</div>
</TabItem>
<TabItem Text="Sign log">
<div>I am Sign log management</div>
</TabItem>
<TabItem Text="Timed task">
<div>I am a timed task manager</div>
</TabItem>
</Tab>
<Divider Text="Split Line"></Divider>
<Tab Placement="@BindPlacement" IsBorderCard="true" Height="200">
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="System logs">
<div>I am a system log</div>
</TabItem>
<TabItem Text="Sign log">
<div>I am Sign log management</div>
</TabItem>
<TabItem Text="Timed task">
<div>I am a timed task manager</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Custom add tab triggers" Introduction="Dynamically add/remove <code>TabItem</code> by calling the component api" Name="AddTabItem">
<p>
<Button Icon="fa fa-plus-circle" OnClickWithoutRender="@(() => AddTab(TabSet))" Text="Add">
</Button>
<Button Color="Color.Danger" Icon="fa fa-minus-circle" IsDisabled="@RemoveEndable" OnClickWithoutRender="@(() => RemoveTab(TabSet))" Text="Rmove">
</Button>
<Button Icon="fa fa-fa" OnClickWithoutRender="@(() => Active(TabSet))" Text="Activate the first one">
</Button>
</p>
<Tab IsBorderCard="true" @ref="TabSet">
<TabItem Text="User">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department ">
<div>I am department management</div>
</TabItem>
<TabItem Text="Timed task">
<div>I am a timed task manager</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Additional components are built in" Introduction="other components are built into the <code>TabItem</code>" Name="Component">
<p>
<code>Tab</code> The contents of each panel of the component remain state by default, and in this case the original data is maintained when the panel switches
</p>
<Tab IsBorderCard="true">
<TabItem Text="Count">
<Counter></Counter>
</TabItem>
<TabItem Text="Weather forecast">
<FetchData></FetchData>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="The program dynamically adds the TabItem panel" Introduction="This feature allows you to click on the menu link in the sidebar and render multiple labels at the top of the data area on the right" Name="DynamicTabItem">
<p>
In this example, the right the <code>Tab</code> the inside of the panel remains in state, and the component reloads when it is closed and reopened
</p>
<Layout SideWidth="120px" style="min-height: 180px; border: 1px solid #ddd; border-radius: 4px;">
<Header>
<div class="header">Header</div>
</Header>
<Side>
<div style="border-right: 1px solid #e6e6e6; height: 100%; overflow: auto; padding: 1rem 0; background-color: #f8f9fa;">
<Menu Items="@GetSideMenuItems()" IsVertical="true" OnClick="@OnClickMenuItem" @ref="TabMenu" />
</div>
</Side>
<Main>
<div class="tab-main-demo">
<Tab @ref="TabSetMenu" ShowClose="true">
</Tab>
</div>
</Main>
</Layout>
</DemoBlock>
<DemoBlock Title="Live Tab components" Introduction="By setting the <code>ShowExtendButtons</code> property to <code>true</code>, turning on the left and right buttons of the component and closing the drop-down menu, it is very useful in practice" Name="App">
<Tips>Dynamically adjust the number of <code>TabItem</code> by <b>adding</b>, <b>delete</b>buttons to view the left and right effects beyond the number of containers, <b>user management</b> is set to not close, and the feature button cannot close this tab</Tips>
<p>
<button type="button" class="btn btn-outline-primary" @onclick="@(e => AddTab(TabSet2))">
<i class="fa fa-plus-circle"></i>
<span>Add</span>
</button>
<button type="button" class="btn btn-outline-danger" disabled="@((TabSet2?.Items.Count() > 4) ? null : "true")" @onclick="@(e => RemoveTab(TabSet2!))">
<i class="fa fa-minus-circle"></i>
<span>Rmove</span>
</button>
</p>
<Tab ShowExtendButtons="true" ShowClose="true" @ref="TabSet2">
<TabItem Text="User" Closable="false">
<div>I am a user manager</div>
</TabItem>
<TabItem Text="Menu">
<div>I am menu management</div>
</TabItem>
<TabItem Text="Roles">
<div>I am roles management</div>
</TabItem>
<TabItem Text="Department ">
<div>I am department management</div>
</TabItem>
<TabItem Text="Timed task">
<div>I am a timed task manager</div>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Only the current label is rendered" Introduction="By setting the <code>isOnlyRenderActiveTab</code> parameter, the component renders only the current active label" Name="IsOnlyRenderActive">
<Tab IsBorderCard="true" IsOnlyRenderActiveTab="true">
<TabItem Text="Count">
<Counter></Counter>
</TabItem>
<TabItem Text="Weather forecast">
<FetchData></FetchData>
</TabItem>
</Tab>
</DemoBlock>
<DemoBlock Title="Header Template" Introduction="customer the header UI via <code>HeaderTemplate</code>" Name="HeaderTemplate">
<Tab IsBorderCard="true">
<TabItem>
<HeaderTemplate>
<div class="@GetClassString(context)" @onclick="() => OnClickTabItem(context)">
<i class="fa fa-tv"></i>
<span class="mx-2">Todo List</span>
<Badge Color="Color.Danger" style="position: absolute; right: 2px; top: 2px;">9</Badge>
</div>
</HeaderTemplate>
<ChildContent>
<div>Use <code>Badge</code> in the <code>HeaderTemplate</code></div>
</ChildContent>
</TabItem>
<TabItem Text="Count">
<Counter></Counter>
</TabItem>
</Tab>
</DemoBlock>
<AttributeTable Items="@GetAttributes()" Title="Attributes" />
<MethodTable Items="@GetMethods()" Title="Method" />
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Components;
using Microsoft.AspNetCore.Components;
namespace BootstrapBlazor.Shared.Samples;
/// <summary>
///
/// </summary>
public sealed partial class Tabs
{
[NotNull]
private Tab? TabSet { get; set; }
[NotNull]
private Tab? TabSet2 { get; set; }
[NotNull]
private string? TabText { get; set; }
[NotNull]
private TabItem? TabItemElement { get; set; }
/// <summary>
///
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
TabText = @Localizer["TabItem8Text"];
}
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
var menuItem = TabMenu?.Items.FirstOrDefault();
if (menuItem != null)
{
await InvokeAsync(() =>
{
var _ = TabMenu?.OnClick?.Invoke(menuItem);
});
}
}
}
private Task AddTab(Tab tabset)
{
var text = $"Tab {tabset.Items.Count() + 1}";
tabset.AddTab(new Dictionary<string, object?>
{
[nameof(TabItem.Text)] = text,
[nameof(TabItem.IsActive)] = true,
[nameof(TabItem.ChildContent)] = new RenderFragment(builder =>
{
var index = 0;
builder.OpenElement(index++, "div");
builder.AddContent(index++, Localizer["BackAddTabText", text]);
builder.CloseElement();
})
});
return Task.CompletedTask;
}
private static Task Active(Tab tabset)
{
tabset.ActiveTab(0);
return Task.CompletedTask;
}
private bool RemoveEndable => (TabSet?.Items.Count() ?? 4) < 4;
private static Task RemoveTab(Tab tabset)
{
if (tabset.Items.Count() > 4)
{
var item = tabset.Items.Last();
tabset.RemoveTab(item);
}
return Task.CompletedTask;
}
private Placement BindPlacement = Placement.Top;
private void SetPlacement(Placement placement)
{
BindPlacement = placement;
}
private IEnumerable<MenuItem> GetSideMenuItems()
{
return new List<MenuItem>
{
new MenuItem() { Text = Localizer["BackText1"] },
new MenuItem() { Text = Localizer["BackText2"] }
};
}
[NotNull]
private Tab? TabSetMenu { get; set; }
[NotNull]
private Menu? TabMenu { get; set; }
private Task OnClickMenuItem(MenuItem item)
{
var text = item.Text;
var tabItem = TabSetMenu.Items.FirstOrDefault(i => i.Text == text);
if (tabItem == null) AddTabItem(text ?? "");
else TabSetMenu.ActiveTab(tabItem);
return Task.CompletedTask;
}
private void AddTabItem(string text) => TabSetMenu.AddTab(new Dictionary<string, object?>
{
[nameof(TabItem.Text)] = text,
[nameof(TabItem.IsActive)] = true,
[nameof(TabItem.ChildContent)] = text == Localizer["BackText1"] ? BootstrapDynamicComponent.CreateComponent<Counter>().Render() : BootstrapDynamicComponent.CreateComponent<FetchData>().Render()
});
private void SetTabItemText()
{
TabText = DateTime.Now.ToString();
}
private static void OnClickTabItem(Tab tab) => tab.ActiveTab(0);
private static string? GetClassString(Tab tab) => CssBuilder.Default("tabs-item")
.AddClass("active", tab.Items.ElementAt(0).IsActive)
.Build();
/// <summary>
/// 获得属性方法
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
// TODO: 移动到数据库中
new AttributeItem() {
Name = "IsBorderCard",
Description = Localizer["Att1"].Value,
Type = "boolean",
ValueList = "true/false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsCard",
Description = Localizer["Att2"].Value,
Type = "boolean",
ValueList = "true/false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsOnlyRenderActiveTab",
Description = Localizer["Att3"].Value,
Type = "boolean",
ValueList = "true/false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "ShowClose",
Description = Localizer["Att4"].Value,
Type = "boolean",
ValueList = "true/false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "ShowExtendButtons",
Description = Localizer["Att5"].Value,
Type = "boolean",
ValueList = " — ",
DefaultValue = "false"
},
new AttributeItem() {
Name = "ClickTabToNavigation",
Description = Localizer["Att6"].Value,
Type = "boolean",
ValueList = "true/false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "Placement",
Description = Localizer["Att7"].Value,
Type = "Placement",
ValueList = "Top|Right|Bottom|Left",
DefaultValue = "Top"
},
new AttributeItem() {
Name = "Height",
Description = Localizer["Att8"].Value,
Type = "int",
ValueList = " — ",
DefaultValue = "0"
},
new AttributeItem() {
Name = "Items",
Description = Localizer["Att9"].Value,
Type = "IEnumerable<TabItemBase>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "DefaultUrl",
Description = Localizer["DefaultUrl"].Value,
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "HeaderTemplate",
Description = Localizer["AttHeaderTemplate"].Value,
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "ChildContent",
Description = Localizer["Att10"].Value,
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "AdditionalAssemblies",
Description = Localizer["Att11"].Value,
Type = "IEnumerable<Assembly>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "OnClickTab",
Description = Localizer["Att12"].Value,
Type = "Func<TabItem, Task>",
ValueList = " — ",
DefaultValue = " — "
}
};
/// <summary>
/// 获得方法
/// </summary>
/// <returns></returns>
private IEnumerable<MethodItem> GetMethods() => new MethodItem[]
{
// TODO: 移动到数据库中
new MethodItem() {
Name = "AddTab",
Description = Localizer["Method1"].Value,
Parameters = "TabItem, int? Index = null",
ReturnValue = " — "
},
new MethodItem() {
Name = "RemoveTab",
Description = Localizer["Method2"].Value,
Parameters = "TabItem",
ReturnValue = " — "
},
new MethodItem() {
Name = "ActiveTab",
Description = Localizer["Method3"].Value,
Parameters = "TabItem",
ReturnValue = " — "
},
new MethodItem() {
Name = "ClickPrevTab",
Description = Localizer["Method4"].Value,
Parameters = "",
ReturnValue = "Task"
},
new MethodItem() {
Name = "ClickNextTab",
Description = Localizer["Method5"].Value,
Parameters = "",
ReturnValue = "Task"
},
new MethodItem() {
Name = "CloseCurrentTab",
Description = Localizer["Method6"].Value,
Parameters = "",
ReturnValue = "Task"
},
new MethodItem() {
Name = "CloseOtherTabs",
Description = Localizer["Method7"].Value,
Parameters = "",
ReturnValue = "Task"
},
new MethodItem() {
Name = "CloseAllTabs",
Description = Localizer["Method8"].Value,
Parameters = "",
ReturnValue = "Task"
},
new MethodItem() {
Name = nameof(Tab.GetActiveTab),
Description = Localizer["Method9"].Value,
Parameters = "",
ReturnValue = "Tabitem"
}
};
}