11---
2- title : Add and Remove Tabs
2+ title : Add and Remove TabStrip Tabs
33description : Learn how to dynamically add and remove tabs
44type : how-to
5- page_title : Add and Remove Tabs
5+ page_title : How to Add and Remove TabStrip Tabs
66slug : tabstrip-kb-add-remove-tabs
77tags : telerik,blazor,tabstrip,add tabs,remove tabs
8- ticketid :
8+ ticketid :
99res_type : kb
10- previous_url : /knowledge-base/tabstrip-dynamic-tabs
1110---
1211
1312## Environment
@@ -21,7 +20,6 @@ previous_url: /knowledge-base/tabstrip-dynamic-tabs
2120 </tbody>
2221</table >
2322
24-
2523## Description
2624
2725I have a collection of items representing separate tabs. I am iterating through that collection to render a tab for each item as shown in the [ Tabs Collection article] ( slug:tabstrip-tabs-collection ) . I want to allow the user to add and remove tabs. How to achieve that?
@@ -35,40 +33,43 @@ This KB article also answers the following questions:
3533
3634## Solution
3735
38- * Use a [ ` HeaderTemplate ` ] ( slug:tabstrip-header-template ) for the tab to add an "X" button.
39- * Display the "X" button only when there is more than one tab.
40- * Declare a "+" button for adding tabs.
41- * Use custom styling and JavaScript to position the "+" button next to the last tab header.
36+ 1 . [ Render the TabStrip tabs in a loop] ( slug:tabstrip-tabs-collection ) .
37+ 1 . Use a [ ` HeaderTemplate ` ] ( slug:tabstrip-header-template ) for the tabs to add Remove buttons. You can display the buttons conditionally based on the tab count.
38+ 1 . Declare a button for adding new tabs.
39+ 1 . Use custom styling and JavaScript to position the Add button next to the last tab header.
40+
41+ > caption Adding and removing TabStrip tabs at runtime
4242
4343```` RAZOR
4444@inject IJSRuntime JS
4545
4646<div class="dynamic-tabstrip-wrapper k-relative">
4747 <TelerikButton OnClick="@AddTab"
4848 Class="add-tab-button !k-absolute k-z-10 k-ratio-1"
49- Icon="@SvgIcon.Plus"
5049 FillMode="@ThemeConstants.Button.FillMode.Flat"
51- ThemeColor="@ThemeConstants.Button.ThemeColor.Primary"
52- Rounded="@ThemeConstants.Button.Rounded.Full" />
50+ Icon="@SvgIcon.Plus"
51+ ThemeColor="@ThemeConstants.Button.ThemeColor.Primary" />
52+
5353 <TelerikTabStrip @bind-ActiveTabId="@ActiveTabId" PersistTabContent="true">
5454 @foreach (Tab tab in Tabs)
5555 {
5656 <TabStripTab @key="tab.Id" Id="@tab.Id">
5757 <HeaderTemplate>
5858 <div class="k-flex-layout k-gap-2">
59- @tab.Title
59+ <span> @tab.Title</span>
6060 @if (Tabs.Count > 1)
6161 {
6262 <TelerikButton OnClick="@(() => RemoveTab(tab))"
6363 Class="remove-tab-button"
64- Icon="@SvgIcon.X"
6564 FillMode="@ThemeConstants.Button.FillMode.Flat"
65+ Icon="@SvgIcon.X"
66+ Size="@ThemeConstants.Button.Size.Small"
6667 ThemeColor="@ThemeConstants.Button.ThemeColor.Primary" />
6768 }
6869 </div>
6970 </HeaderTemplate>
7071 <Content>
71- Content for @tab.Title
72+ Content for <strong> @tab.Title</strong>
7273 </Content>
7374 </TabStripTab>
7475 }
@@ -95,45 +96,54 @@ This KB article also answers the following questions:
9596 }
9697</style>
9798
99+ @* Move JavaScript code to a JS file *@
98100<script suppress-error="BL9992">
99101 window.positionAddTabButton = () => {
100- const tabStripItems = Array.from(document.querySelectorAll(".dynamic-tabstrip-wrapper .k-tabstrip-item"));
101- const tabStripWrapperWidth = document.querySelector(".dynamic-tabstrip-wrapper").scrollWidth;
102+ const tabStripItems = Array.from(document.querySelectorAll(".dynamic-tabstrip-wrapper .k-tabstrip-item"));
103+ const tabStripWrapperWidth = document.querySelector(".dynamic-tabstrip-wrapper").scrollWidth;
102104
103- let totalWidth = !tabStripItems ? 0 : tabStripItems.reduce(
104- (accumulator, currentItem) => accumulator + parseFloat(currentItem.getBoundingClientRect().width),
105- 0,
106- );
105+ let totalWidth = !tabStripItems ? 0 : tabStripItems.reduce(
106+ (accumulator, currentItem) => accumulator + parseFloat(currentItem.getBoundingClientRect().width),
107+ 0,
108+ );
107109
108- const addTabButton = document.querySelector(".add-tab-button");
109- const addTabButtonWidth = addTabButton.getBoundingClientRect().width;
110+ const addTabButton = document.querySelector(".add-tab-button");
111+ const addTabButtonWidth = addTabButton.getBoundingClientRect().width;
110112
111- // Assure button is never positioned outside the boundaries of the wrapper
112- if (totalWidth + addTabButtonWidth > tabStripWrapperWidth) {
113- totalWidth = tabStripWrapperWidth - addTabButtonWidth;
114- }
113+ // assure button is never positioned outside the boundaries of the wrapper
114+ if (totalWidth + addTabButtonWidth > tabStripWrapperWidth) {
115+ totalWidth = tabStripWrapperWidth - addTabButtonWidth;
116+ }
115117
116- addTabButton.style.left = `${totalWidth}px`;
118+ addTabButton.style.left = `${totalWidth}px`;
117119 };
118120</script>
119121
120- @code {
121- private string ActiveTabId { get; set; } = string.Empty;
122122
123- private List<Tab> Tabs = new List<Tab>
123+ @code {
124+ private List<Tab> Tabs = new List<Tab>()
124125 {
125- new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 1" },
126- new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 2" },
127- new Tab { Id = Guid.NewGuid().ToString(), Title = "Tab 3" }
126+ new Tab { Title = "Tab 1" },
127+ new Tab { Title = "Tab 2" },
128+ new Tab { Title = "Tab 3" }
128129 };
129130
131+ private string ActiveTabId { get; set; } = string.Empty;
132+
133+ private bool ShouldPositionAddButton { get; set; }
134+
135+ private int LastTabNumber { get; set; } = 3;
136+
130137 private void AddTab()
131138 {
132- var tabToAdd = new Tab { Id = Guid.NewGuid().ToString(), Title = "New Tab" };
139+ Tab tabToAdd = new Tab { Id = Guid.NewGuid().ToString(), Title = $"New Tab {++LastTabNumber}" };
140+
133141 Tabs.Add(tabToAdd);
134142
135- // Activate the newly added tab
143+ //In this example, we are always activating the newly added tab. Adjust the logic to activate a different tab if needed.
136144 ActiveTabId = tabToAdd.Id;
145+
146+ ShouldPositionAddButton = true;
137147 }
138148
139149 private void RemoveTab(Tab tab)
@@ -143,26 +153,47 @@ This KB article also answers the following questions:
143153 return;
144154 }
145155
156+ // Activate the tab after or before the removed one if it's active
157+ if (ActiveTabId == tab.Id)
158+ {
159+ int removedTabIndex = Tabs.FindIndex(x => x.Id == tab.Id);
160+ if (removedTabIndex == Tabs.Count - 1)
161+ {
162+ ActiveTabId = Tabs.ElementAt(removedTabIndex - 1).Id;
163+ }
164+ else
165+ {
166+ ActiveTabId = Tabs.ElementAt(removedTabIndex + 1).Id;
167+ }
168+ }
169+
146170 Tabs.Remove(tab);
147171
148- // Activate the first tab after removal
149- ActiveTabId = Tabs[0].Id;
172+ ShouldPositionAddButton = true;
150173 }
151174
152175 protected override async Task OnAfterRenderAsync(bool firstRender)
153176 {
154- await JS.InvokeVoidAsync("positionAddTabButton");
177+ if (firstRender || ShouldPositionAddButton)
178+ {
179+ ShouldPositionAddButton = false;
180+ await JS.InvokeVoidAsync("positionAddTabButton");
181+ }
182+
155183 await base.OnAfterRenderAsync(firstRender);
156184 }
157185
158186 public class Tab
159187 {
160- public string Id { get; set; } = string.Empty;
188+ public string Id { get; set; } = Guid.NewGuid().ToString();
189+
161190 public string Title { get; set; } = string.Empty;
162191 }
192+
163193}
164194````
165195
166196## See Also
167197
168- * [ Dynamic Tabs] ( slug:tabstrip-tabs-collection )
198+ * [ Dynamic Tab Collection] ( slug:tabstrip-tabs-collection )
199+ * [ TabStrip Tab ` HeaderTemplate ` ] ( slug:tabstrip-header-template )
0 commit comments