Skip to content

Commit e6b4284

Browse files
committed
chore(TabStrip): add kb for adding and removing tabs
1 parent 9e6849f commit e6b4284

File tree

3 files changed

+182
-37
lines changed

3 files changed

+182
-37
lines changed

components/tabstrip/tabs-collection.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ To deactivate all tabs, set the ActiveTabId parameter to `string.Empty`.
2727
@{
2828
foreach (var tab in Tabs)
2929
{
30-
<TabStripTab @key="tab.Id" Title="@tab.Title" Visible="@tab.Visible" Disabled="@tab.Disabled">
30+
<TabStripTab @key="tab.Id" Id="@tab.Id" Title="@tab.Title" Visible="@tab.Visible" Disabled="@tab.Disabled">
3131
<HeaderTemplate>
3232
<span>@tab.Title</span>
3333
</HeaderTemplate>
@@ -54,11 +54,11 @@ To deactivate all tabs, set the ActiveTabId parameter to `string.Empty`.
5454
private string ActiveTabId { get; set; }
5555
5656
private List<Tab> Tabs { get; set; } = new List<Tab>
57-
{
58-
new Tab { Id = "home", Title = "🏠 Home", Visible = true, Disabled = false },
59-
new Tab { Id = "profile", Title = "👤 Profile", Visible = true, Disabled = false },
60-
new Tab { Id = "settings", Title = "⚙️ Settings", Visible = true, Disabled = false }
61-
};
57+
{
58+
new Tab { Id = "home", Title = "🏠 Home", Visible = true, Disabled = false },
59+
new Tab { Id = "profile", Title = "👤 Profile", Visible = true, Disabled = false },
60+
new Tab { Id = "settings", Title = "⚙️ Settings", Visible = true, Disabled = false }
61+
};
6262
6363
public class Tab
6464
{
@@ -70,6 +70,11 @@ To deactivate all tabs, set the ActiveTabId parameter to `string.Empty`.
7070
}
7171
````
7272

73+
## Add and Remove Tabs
74+
75+
If you are iterating through a collection to render the tabs and you need to allow the users to add and remove tabs, you may use the `ActiveTabId` parameter to set the active tab after adding and removing tabs. See details and example in this article: [Add and Remove Tabs](slug:tabstrip-kb-add-remove-tabs).
76+
77+
7378
## See Also
7479

7580
* [TabStrip Events](slug:tabstrip-events)
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
---
2+
title: Add and Remove Tabs
3+
description: Learn how to dynamically add and remove tabs
4+
type: how-to
5+
page_title: Add and Remove Tabs
6+
slug: tabstrip-kb-add-remove-tabs
7+
tags: telerik,blazor,tabstrip,add tabs,remove tabs
8+
ticketid:
9+
res_type: kb
10+
previous_url: /knowledge-base/tabstrip-dynamic-tabs
11+
---
12+
13+
## Environment
14+
15+
<table>
16+
<tbody>
17+
<tr>
18+
<td>Product</td>
19+
<td>TabStrip for Blazor</td>
20+
</tr>
21+
</tbody>
22+
</table>
23+
24+
25+
## Description
26+
27+
I have a collection of items representing separate tabs. I am iterating through that collection to render a tab for each item as shown [here](slug:tabstrip-tabs-collection). I want to allow the user to add and remove tabs, how to achieve that?
28+
29+
This KB article answers the following questions:
30+
31+
* How to remove a tab with a "X" button in the tab header?
32+
* How to use a button to add tabs and position this button next to the last tab header (similar to the "+" button in the browser)?
33+
34+
## Solution
35+
36+
The example below shows how to:
37+
* Use a [`HeaderTemplate`](slug:tabstrip-header-template) for the tab to add a button that removes the tab.
38+
* Conditionally display the "X" button based on the tabs' count.
39+
* Declare a button for adding tabs.
40+
* Use custom styling and JavaScript to position the "+" button next to the last tab header.
41+
42+
````RAZOR
43+
@inject IJSRuntime JS
44+
45+
<style>
46+
.dynamic-tabstrip-wrapper {
47+
--add-tab-button-size: 32.8px;
48+
}
49+
50+
.dynamic-tabstrip-wrapper .k-tabstrip-items {
51+
max-width: calc(100% - var(--add-tab-button-size));
52+
}
53+
54+
.dynamic-tabstrip-wrapper .add-tab-button {
55+
width: var(--add-tab-button-size);
56+
padding-block: 6px;
57+
z-index: 10000;
58+
}
59+
60+
.remove-tab-button {
61+
padding: 0 !important;
62+
}
63+
</style>
64+
65+
<div class="dynamic-tabstrip-wrapper k-relative">
66+
<TelerikButton OnClick="@AddTab"
67+
Class="add-tab-button !k-absolute k-z-10 k-ratio-1"
68+
Icon="@SvgIcon.Plus"
69+
FillMode="@ThemeConstants.Button.FillMode.Flat"
70+
ThemeColor="@ThemeConstants.Button.ThemeColor.Primary"
71+
Rounded="@ThemeConstants.Button.Rounded.Full" />
72+
<TelerikTabStrip @bind-ActiveTabId="@ActiveTabId" PersistTabContent="true">
73+
@foreach (Tab tab in Tabs)
74+
{
75+
<TabStripTab @key="tab.Id" Id="@tab.Id">
76+
<HeaderTemplate>
77+
<div class="k-flex-layout k-gap-2">
78+
@tab.Title
79+
@if (Tabs.Count > 1)
80+
{
81+
<TelerikButton OnClick="@(() => RemoveTab(tab))"
82+
Class="remove-tab-button"
83+
Icon="@SvgIcon.X"
84+
FillMode="@ThemeConstants.Button.FillMode.Flat"
85+
ThemeColor="@ThemeConstants.Button.ThemeColor.Primary" />
86+
}
87+
</div>
88+
</HeaderTemplate>
89+
<Content>
90+
Content for @tab.Title
91+
</Content>
92+
</TabStripTab>
93+
}
94+
</TelerikTabStrip>
95+
</div>
96+
97+
@code {
98+
private string ActiveTabId { get; set; }
99+
100+
private List<Tab> Tabs = new List<Tab>()
101+
{
102+
new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 1" },
103+
new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 2" },
104+
new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 3" }
105+
};
106+
107+
private void AddTab()
108+
{
109+
Tab tabToAdd = new Tab { Id = Guid.NewGuid().ToString(), Title = $"New Tab" };
110+
111+
Tabs.Add(tabToAdd);
112+
113+
//In this example, we are always activating the newly added tab. Adjust the logic to activate a different tab if needed.
114+
ActiveTabId = tabToAdd.Id;
115+
}
116+
117+
private void RemoveTab(Tab tab)
118+
{
119+
if (Tabs.Count <= 1)
120+
{
121+
return;
122+
}
123+
124+
Tabs.Remove(tab);
125+
126+
//In this example, we are always activating the first tab. Adjust the logic to determine which tab to activate after removal.
127+
ActiveTabId = Tabs[0].Id;
128+
}
129+
130+
protected override async Task OnAfterRenderAsync(bool firstRender)
131+
{
132+
await JS.InvokeVoidAsync("positionAddTabButton");
133+
134+
await base.OnAfterRenderAsync(firstRender);
135+
}
136+
137+
public class Tab
138+
{
139+
public string Id { get; set; }
140+
141+
public string Title { get; set; }
142+
}
143+
144+
}
145+
146+
<script suppress-error="BL9992">
147+
window.positionAddTabButton = () => {
148+
const tabStripItems = Array.from(document.querySelectorAll(".dynamic-tabstrip-wrapper .k-tabstrip-item"));
149+
const tabStripWrapperWidth = document.querySelector(".dynamic-tabstrip-wrapper").scrollWidth;
150+
151+
let totalWidth = !tabStripItems ? 0 : tabStripItems.reduce(
152+
(accumulator, currentItem) => accumulator + parseFloat(currentItem.getBoundingClientRect().width),
153+
0,
154+
);
155+
156+
const addTabButton = document.querySelector(".add-tab-button");
157+
const addTabButtonWidth = addTabButton.getBoundingClientRect().width;
158+
159+
// assure button is never positioned outside the boundaries of the wrapper
160+
if (totalWidth + addTabButtonWidth > tabStripWrapperWidth) {
161+
totalWidth = tabStripWrapperWidth - addTabButtonWidth;
162+
}
163+
164+
addTabButton.style.left = `${totalWidth}px`;
165+
};
166+
</script>
167+
````
168+
169+
## See Also
170+
171+
* [Dynamic Tabs](slug:tabstrip-tabs-collection)

knowledge-base/tabstrip-dynamic-tabs.md

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)