diff --git a/packages/calcite-components/src/components.d.ts b/packages/calcite-components/src/components.d.ts index 1c920006dcc..1c2de4bd221 100644 --- a/packages/calcite-components/src/components.d.ts +++ b/packages/calcite-components/src/components.d.ts @@ -4873,8 +4873,6 @@ export namespace Components { } interface CalciteTabNav { "bordered": boolean; - "indicatorOffset": number; - "indicatorWidth": number; "layout": TabLayout; /** * Use this property to override individual strings used by the component. @@ -12878,8 +12876,6 @@ declare namespace LocalJSX { } interface CalciteTabNav { "bordered"?: boolean; - "indicatorOffset"?: number; - "indicatorWidth"?: number; "layout"?: TabLayout; /** * Use this property to override individual strings used by the component. diff --git a/packages/calcite-components/src/components/tab-nav/resources.ts b/packages/calcite-components/src/components/tab-nav/resources.ts index 451228247f6..010d3306dfa 100644 --- a/packages/calcite-components/src/components/tab-nav/resources.ts +++ b/packages/calcite-components/src/components/tab-nav/resources.ts @@ -4,7 +4,6 @@ export const ICON = { } as const; export const CSS = { - activeIndicatorContainer: "tab-nav-active-indicator-container", container: "tab-nav", containerHasEndTabTitleOverflow: "tab-nav--end-overflow", containerHasStartTabTitleOverflow: "tab-nav--start-overflow", diff --git a/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts b/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts index e9d2be1069d..df4fe3bfd73 100644 --- a/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts +++ b/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts @@ -48,48 +48,6 @@ describe("calcite-tab-nav", () => { expect(activeEventSpy).toHaveReceivedEventTimes(2); }); - describe("selected indicator", () => { - const tabTitles = html` - Tab 1 Title - Tab 2 Title - Tab 3 Title - Tab 4 Title - `; - - it("has its active indicator positioned from left if LTR", async () => { - const page = await newE2EPage(); - await page.setContent(`${tabTitles}`); - const element = await page.find("calcite-tab-nav >>> .tab-nav-active-indicator"); - const style = await element.getComputedStyle(); - expect(style["left"]).toBe("0px"); - expect(style["right"]).not.toBe("0px"); - expect(style["width"]).not.toBe("0px"); - }); - - it("has its active indicator positioned from right if RTL", async () => { - const page = await newE2EPage(); - await page.setContent(`${tabTitles}`); - const element = await page.find("calcite-tab-nav >>> .tab-nav-active-indicator"); - const style = await element.getComputedStyle(); - expect(style["right"]).toBe("0px"); - expect(style["left"]).not.toBe("0px"); - expect(style["width"]).not.toBe("0px"); - }); - - it("updates position when made visible", async () => { - const page = await newE2EPage(); - await page.setContent(``); - const tabNav = await page.find("calcite-tab-nav"); - const indicator = await page.find("calcite-tab-nav >>> .tab-nav-active-indicator"); - - tabNav.setProperty("hidden", false); - await page.waitForChanges(); - - const style = await indicator.getComputedStyle(); - expect(style["width"]).not.toBe("0px"); - }); - }); - it("focuses on keyboard interaction", async () => { const page = await newE2EPage(); await page.setContent( diff --git a/packages/calcite-components/src/components/tab-nav/tab-nav.scss b/packages/calcite-components/src/components/tab-nav/tab-nav.scss index ff0279df298..aedd6d89ffb 100644 --- a/packages/calcite-components/src/components/tab-nav/tab-nav.scss +++ b/packages/calcite-components/src/components/tab-nav/tab-nav.scss @@ -28,7 +28,6 @@ $last-mask-color-stop-position: 51%; // we go beyond the half point to ensure the mask color stops overlap when both start and end are overflowing .tab-nav--start-overflow { - .tab-nav-active-indicator-container, .tab-titles-slot-wrapper { mask-image: linear-gradient( to var(--calcite-internal-tab-nav-gradient-end-side), @@ -41,7 +40,6 @@ $last-mask-color-stop-position: 51%; // we go beyond the half point to ensure th } .tab-nav--end-overflow { - .tab-nav-active-indicator-container, .tab-titles-slot-wrapper { mask-image: linear-gradient( to var(--calcite-internal-tab-nav-gradient-start-side), @@ -54,7 +52,6 @@ $last-mask-color-stop-position: 51%; // we go beyond the half point to ensure th } .tab-nav--start-overflow.tab-nav--end-overflow { - .tab-nav-active-indicator-container, .tab-titles-slot-wrapper { mask-image: linear-gradient( to var(--calcite-internal-tab-nav-gradient-end-side), @@ -126,26 +123,6 @@ $last-mask-color-stop-position: 51%; // we go beyond the half point to ensure th overflow-hidden; } -// prevent indicator overflow in horizontal scrolling situations -.tab-nav-active-indicator-container { - @apply absolute - bottom-0 - h-0.5 - inset-x-0 - overflow-hidden - w-full; -} - -.tab-nav-active-indicator { - @apply absolute - bg-brand - bottom-0 - block - h-0.5 - ease-out - transition-all; -} - .scroll-button-container { @apply absolute bottom-0 top-0; @@ -195,29 +172,4 @@ $last-mask-color-stop-position: 51%; // we go beyond the half point to ensure th } } -:host .position-bottom .tab-nav-active-indicator { - inset-block-end: unset; - @apply top-0; -} - -:host .position-bottom .tab-nav-active-indicator-container { - inset-block-end: unset; - @apply top-0; -} - -:host([bordered]) .tab-nav-active-indicator-container { - inset-block-end: unset; // display active blue line above instead of below -} - -:host([bordered]) .position-bottom .tab-nav-active-indicator-container { - inset-block-end: 0; // display active blue line below instead of above - inset-block-start: unset; -} - -@media (forced-colors: active) { - .tab-nav-active-indicator { - background-color: highlight; - } -} - @include base-component(); diff --git a/packages/calcite-components/src/components/tab-nav/tab-nav.tsx b/packages/calcite-components/src/components/tab-nav/tab-nav.tsx index adaccde7ceb..ab5d5f1c958 100644 --- a/packages/calcite-components/src/components/tab-nav/tab-nav.tsx +++ b/packages/calcite-components/src/components/tab-nav/tab-nav.tsx @@ -79,7 +79,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { this.calciteInternalTabChange.emit({ tab: this.selectedTabId, }); - this.updateActiveIndicator(); } /** @@ -106,16 +105,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { */ @Prop({ reflect: true, mutable: true }) bordered = false; - /** - * @internal - */ - @Prop({ mutable: true }) indicatorOffset: number; - - /** - * @internal - */ - @Prop({ mutable: true }) indicatorWidth: number; - /** * Made into a prop for testing purposes only. * @@ -167,10 +156,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { this.layout = parentTabsEl?.layout; this.bordered = parentTabsEl?.bordered; this.effectiveDir = getElementDir(this.el); - - if (this.selectedTitle) { - this.updateActiveIndicator(); - } } componentDidRender(): void { @@ -201,11 +186,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { //-------------------------------------------------------------------------- render(): VNode { - const width = `${this.indicatorWidth}px`; - const offset = `${this.indicatorOffset}px`; - const indicatorStyle = - this.effectiveDir !== "rtl" ? { width, left: offset } : { width, right: offset }; - return (
{this.renderScrollButton("start")}
-
(this.activeIndicatorContainerEl = el)} - > -
(this.activeIndicatorEl = el as HTMLElement)} - style={indicatorStyle} - /> -
{this.renderScrollButton("end")}
@@ -367,11 +334,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { event.stopPropagation(); } - @Listen("calciteInternalTabIconChanged") - iconStartChangeHandler(): void { - this.updateActiveIndicator(); - } - //-------------------------------------------------------------------------- // // Events @@ -432,12 +394,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { }); } - private activeIndicatorEl: HTMLElement; - - private activeIndicatorContainerEl: HTMLDivElement; - - private containerEl: HTMLDivElement; - private effectiveDir: Direction = "ltr"; private lastScrollWheelAxis: "x" | "y" = "x"; @@ -450,12 +406,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { private resizeObserver = createObserver("resize", () => { this.updateScrollingState(); - - if (!this.activeIndicatorEl) { - return; - } - - this.updateActiveIndicator(); }); private get scrollerButtonWidth(): number { @@ -469,20 +419,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { // //-------------------------------------------------------------------------- - private updateActiveIndicator(): void { - const tabTitleScrollLeft = this.tabTitleContainerEl?.scrollLeft; - const containerScrollLeft = this.containerEl?.scrollLeft; - const navWidth = this.activeIndicatorContainerEl?.offsetWidth; - const tabLeft = this.selectedTitle?.offsetLeft; - const tabWidth = this.selectedTitle?.offsetWidth; - const offsetRight = navWidth - tabLeft - tabWidth; - const offsetBase = this.effectiveDir === "ltr" ? tabLeft : offsetRight; - const multiplier = this.effectiveDir === "ltr" ? -1 : 1; - - this.indicatorOffset = offsetBase + multiplier * (containerScrollLeft + tabTitleScrollLeft); - this.indicatorWidth = this.selectedTitle?.offsetWidth; - } - private onTabTitleWheel = (event: WheelEvent): void => { event.preventDefault(); @@ -504,7 +440,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { const scrollByX = (this.effectiveDir === "rtl" ? -1 : 1) * scrollBy; (event.currentTarget as HTMLDivElement).scrollBy(scrollByX, 0); - requestAnimationFrame(() => this.updateActiveIndicator()); }; private onSlotChange = (event: Event): void => { @@ -517,8 +452,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { this.calciteInternalTabNavSlotChange.emit(slottedElements); }; - private storeContainerRef = (el: HTMLDivElement) => (this.containerEl = el); - private storeTabTitleWrapperRef = (el: HTMLDivElement) => { this.tabTitleContainerEl = el; this.intersectionObserver = createObserver("intersection", () => this.updateScrollingState(), { @@ -646,7 +579,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { } private onTabTitleScroll = (): void => { - this.updateActiveIndicator(); this.updateScrollingState(); }; @@ -699,7 +631,6 @@ export class TabNav implements LocalizedComponent, T9nComponent { } requestAnimationFrame(() => { - this.updateActiveIndicator(); tabTitles[this.selectedTabId].focus(); }); } diff --git a/packages/calcite-components/src/components/tab-title/resources.ts b/packages/calcite-components/src/components/tab-title/resources.ts index f0d85f55681..a2891547cb3 100644 --- a/packages/calcite-components/src/components/tab-title/resources.ts +++ b/packages/calcite-components/src/components/tab-title/resources.ts @@ -1,12 +1,17 @@ +import { Scale } from "../interfaces"; + export const CSS = { closeButton: "close-button", container: "container", + containerBottom: "container--bottom", content: "content", contentHasText: "content--has-text", iconEnd: "icon-end", iconPresent: "icon-present", iconStart: "icon-start", titleIcon: "calcite-tab-title--icon", + scale: (scale: Scale) => `scale-${scale}` as const, + selectedIndicator: "selected-indicator", }; export const ICONS = { diff --git a/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts b/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts index d9ad2e31879..3146dba8ca5 100644 --- a/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts +++ b/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts @@ -343,54 +343,4 @@ describe("calcite-tab-title", () => { await page.keyboard.press("Enter"); expect(activeEventSpy).toHaveReceivedEventTimes(2); }); - - describe("when the active tab-title changes", () => { - it("should move the active tab nav indicator", async () => { - const page = await newE2EPage({ - html: ` - - - Tab 1 Title - Tab 2 Title - Tab 3 Title - Tab 4 Title - - Tab 1 Content - Tab 2 Content - Tab 3 Content - Tab 4 Content - - `, - }); - const tabTitle1 = await page.find(".title-1"); - const tabTitle2 = await page.find(".title-2"); - - expect(await (await page.find("calcite-tab-title[selected]")).innerText).toEqual("Tab 2 Title"); - expect( - await page.evaluate(() => { - return ( - document - .querySelector("calcite-tab-nav") - .shadowRoot.querySelector(".tab-nav-active-indicator") as HTMLDivElement - ).style.left; - }), - ).not.toEqual("0px"); - - // toggle new selected tab-title - await tabTitle2.removeAttribute("selected"); - await tabTitle1.setAttribute("selected", true); - await page.waitForChanges(); - - expect(await (await page.find("calcite-tab-title[selected]")).innerText).toEqual("Tab 1 Title"); - expect( - await page.evaluate(() => { - return ( - document - .querySelector("calcite-tab-nav") - .shadowRoot.querySelector(".tab-nav-active-indicator") as HTMLDivElement - ).style.left; - }), - ).toEqual("0px"); - }); - }); }); diff --git a/packages/calcite-components/src/components/tab-title/tab-title.scss b/packages/calcite-components/src/components/tab-title/tab-title.scss index f995706fe33..9be58245133 100644 --- a/packages/calcite-components/src/components/tab-title/tab-title.scss +++ b/packages/calcite-components/src/components/tab-title/tab-title.scss @@ -12,29 +12,38 @@ } .content { - @apply flex items-center justify-center; + @apply flex items-center justify-center h-full mb-0.5 relative box-border; } .scale-s { .content { @apply text-n2h py-1; } + .close-button { + @apply w-5; + } } .scale-m { .content { @apply text-n1h py-2; } + .close-button { + @apply w-7; + } } .scale-l { .content { @apply text-0h py-2.5; } + .close-button { + @apply w-8; + } } :host([closable]) .content { - @apply h-full box-border border-b-color-transparent; + @apply border-b-color-transparent; } :host([layout="inline"]), @@ -55,8 +64,7 @@ } .container { - @apply border-b-2 - border-b-color-transparent + @apply relative box-border content-center cursor-pointer @@ -69,15 +77,82 @@ text-n1h transition-default w-full; +} + +.selected-indicator { + @apply absolute + block + w-full + h-0.5 + transition-default; + inset-block-end: 0; + inset-inline-start: 0; + inset-inline-end: 0; + inline-size: 100%; +} + +.container--bottom .selected-indicator { + inset-block-end: unset; + inset-block-start: 0; +} + +:host([bordered]) .selected-indicator { + inset-block-start: 0; + inset-block-end: unset; + inset-inline-start: -1px; + inset-inline-end: 0; + inline-size: calc(100% + var(--calcite-spacing-base)); +} + +:host([bordered][selected]) .container::after { + @apply absolute + block + w-full + h-0.5 + transition-default; + inset-block-end: 0; + inset-inline-start: 0; + inset-inline-end: 0; + inline-size: 100%; + background: var(--calcite-color-foreground-1); + content: ""; +} - border-block-end-style: solid; +:host([bordered][selected]) .container.container--bottom::after { + inset-block-start: -1px; } -:host([position="bottom"]) .container { - @apply border-t-color-transparent - border-b-0 - border-t-2; - border-block-start-style: solid; +:host([bordered][selected]:hover) .container::after { + background: var(--calcite-color-foreground-2); +} + +:host([bordered][selected]:focus) .container::after { + background: transparent; +} + +:host([bordered]) .container--bottom .selected-indicator { + inset-block-start: unset; + inset-block-end: 0; +} + +:host([selected]) .selected-indicator, +:host([selected]:hover) .selected-indicator { + @apply bg-brand; +} + +:host(:hover) .selected-indicator { + background-color: var(--calcite-color-border-3); +} + +:host(:focus) .selected-indicator, +:host(:active) .selected-indicator { + background-color: var(--calcite-color-brand); +} + +@media (forced-colors: active) { + .selected-indicator { + background-color: highlight; + } } :host([closed]) { @@ -125,11 +200,11 @@ } .content--has-text .calcite-tab-title--icon.icon-start { - margin-inline-end: theme("margin.2"); + margin-inline-end: var(--calcite-spacing-sm); } .content--has-text .calcite-tab-title--icon.icon-end { - margin-inline-start: theme("margin.2"); + margin-inline-start: var(--calcite-spacing-sm); } .close-button { @@ -142,25 +217,29 @@ focus-base items-center justify-center - p-1 + h-full self-center text-color-3 transition-default; - background-color: var(--calcite-button-transparent-1); - margin-inline-start: auto; + // compensate for the added border on parent and ensure focus alignment + margin-inline-end: var(--calcite-spacing-px); + box-shadow: + var(--calcite-spacing-px) 0 0 0 transparent, + 0 var(--calcite-spacing-xxs) 0 0 transparent; + block-size: calc(100% - var(--calcite-spacing-xxs)); + &:hover { + box-shadow: var(--calcite-spacing-px) 0 0 0 var(--calcite-color-foreground-3); + } &:focus { - @apply focus-inset; - - // ⚠️overriding outline-offset should be avoided as it won't honor --calcite-color-focus-offset-invert - outline-offset: -1px; + @apply focus-normal; } &:focus, &:hover { @apply text-color-1; - background-color: var(--calcite-color-foreground-2); + background-color: var(--calcite-color-foreground-3); } &:active { @@ -176,7 +255,7 @@ // compensate for spacing when no hastext and two icons :host([icon-start][icon-end]) { .calcite-tab-title--icon:first-child { - margin-inline-end: theme("margin.2"); + margin-inline-end: var(--calcite-spacing-sm); } } @@ -186,33 +265,28 @@ } :host([bordered][selected]) { - box-shadow: inset 0 -2px var(--calcite-color-foreground-1); + box-shadow: inset 0 -1px var(--calcite-color-foreground-1); } :host([bordered][selected][position="bottom"]) { - box-shadow: inset 0 2px 0 var(--calcite-color-foreground-1); + box-shadow: inset 0 var(--calcite-spacing-base) 0 var(--calcite-color-foreground-1); } :host([bordered]:hover) { .container { - background-color: var(--calcite-color-transparent-hover); + background-color: var(--calcite-color-foreground-2); } } :host([closable]) .container, :host([bordered]) .container { - border-inline-start: 1px solid transparent; - border-inline-end: 1px solid transparent; + border-inline-start: var(--calcite-spacing-px) solid transparent; + border-inline-end: var(--calcite-spacing-px) solid transparent; .close-button { - margin-inline: 0; + margin-inline-start: var(--calcite-spacing-sm); } } -:host([closable][position="bottom"]) .container, -:host([bordered][position="bottom"]) .container { - border-block-start-style: unset; -} - :host([selected][bordered]) .container { border-inline-start-color: var(--calcite-color-border-1); border-inline-end-color: var(--calcite-color-border-1); @@ -263,7 +337,7 @@ border-block-end-style: solid; } - :host([bordered][position="bottom"]) .container { + :host([bordered]) .container--bottom { border-block-start-style: solid; } @@ -271,7 +345,7 @@ border-block-end-style: none; } - :host([bordered][position="bottom"][selected]) .container { + :host([bordered][selected]) .container--bottom { border-block-start-style: none; } diff --git a/packages/calcite-components/src/components/tab-title/tab-title.tsx b/packages/calcite-components/src/components/tab-title/tab-title.tsx index 7ff878514d5..8d79c1d504d 100644 --- a/packages/calcite-components/src/components/tab-title/tab-title.tsx +++ b/packages/calcite-components/src/components/tab-title/tab-title.tsx @@ -220,9 +220,10 @@ export class TabTitle implements InteractiveComponent, LocalizedComponent, T9nCo {this.renderCloseButton()} +
diff --git a/packages/calcite-components/src/components/tabs/tabs.e2e.ts b/packages/calcite-components/src/components/tabs/tabs.e2e.ts index 98bd01bf3f2..819afba39c5 100644 --- a/packages/calcite-components/src/components/tabs/tabs.e2e.ts +++ b/packages/calcite-components/src/components/tabs/tabs.e2e.ts @@ -172,44 +172,6 @@ describe("calcite-tabs", () => { expect(await page.find("calcite-tab-title")).toEqualAttribute("bordered", ""); expect(await page.find("calcite-tab")).toEqualAttribute("bordered", null); }); - - it("should render tab-nav's blue active indicator on top", async () => { - const page = await newE2EPage({ - html: ` - - - Tab 1 Title - Tab 2 Title - - Tab 1 Content - Tab 2 Content - - `, - }); - const indicator = await page.find("calcite-tab-nav >>> .tab-nav-active-indicator-container"); - const indicatorStyles = await indicator.getComputedStyle(); - expect(indicatorStyles.top).toEqual("0px"); - expect(indicatorStyles.bottom).not.toEqual("0px"); - }); - - it("should render tab-nav's blue active indicator on bottom when position is bottom", async () => { - const page = await newE2EPage({ - html: ` - - - Tab 1 Title - Tab 2 Title - - Tab 1 Content - Tab 2 Content - - `, - }); - const indicator = await page.find("calcite-tab-nav >>> .tab-nav-active-indicator-container"); - const indicatorStyles = await indicator.getComputedStyle(); - expect(indicatorStyles.bottom).toEqual("0px"); - expect(indicatorStyles.top).not.toEqual("0px"); - }); }); it("should not ignore bordered attribute when layout is center", async () => { diff --git a/packages/calcite-components/src/components/tabs/tabs.stories.ts b/packages/calcite-components/src/components/tabs/tabs.stories.ts index 853d6f4924d..ee41fdb436a 100644 --- a/packages/calcite-components/src/components/tabs/tabs.stories.ts +++ b/packages/calcite-components/src/components/tabs/tabs.stories.ts @@ -364,26 +364,6 @@ Tab200PercentHeightWithVerticalScroll.parameters = { chromatic: { delay: 1000 }, }; -export const updateIndicatorOffset_TestOnly = (): string => - html` - - Boats - Ships - Yachts - - Tab 1 content - Tab 2 content - Tab 3 content - - `; - -updateIndicatorOffset_TestOnly.parameters = { - chromatic: { delay: 1000 }, -}; - export const fixedHeightNoVerticalScrollbar_TestOnly = (): string => html` diff --git a/packages/calcite-components/src/demos/tabs.html b/packages/calcite-components/src/demos/tabs.html index c1170a0952a..866245228a4 100644 --- a/packages/calcite-components/src/demos/tabs.html +++ b/packages/calcite-components/src/demos/tabs.html @@ -71,6 +71,7 @@ Tab 1 Title Tab 2 Title Tab 3 Title + Tab 4 Title
@@ -85,6 +86,7 @@ Tab 1 Title Tab 2 Title Tab 3 Title + Tab 4 Title Tab 1 Content Tab 2 Content @@ -129,6 +131,7 @@ Tab 1 Title Tab 2 Title Tab 3 Title + Tab 4 Title Tab 1 Content Tab 2 Content @@ -291,16 +294,80 @@ + +
+
icon end closable
+ +
+ + + Tab 1 Title + Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title + + + Tab 1 Content + Tab 2 Content + +
+ +
+ + + Tab 1 Title + Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title + + + Tab 1 Content + Tab 2 Content + +
+ +
+ + + Tab 1 Title + Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title + + + Tab 1 Content + Tab 2 Content + +
+
with border + icon-start + icon end
- + - Tab 1 Title + Tab 1 Title Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title Tab 1 content Tab 2 Content @@ -308,10 +375,16 @@
- + - Tab 1 Title + Tab 1 Title Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title Tab 1 content Tab 2 Content @@ -319,10 +392,72 @@
- + - Tab 1 Title + Tab 1 Title Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title + + Tab 1 content + Tab 2 Content + +
+
+ + +
+
with border + icon-start + icon end closable
+ +
+ + + Tab 1 Title + Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title + + Tab 1 content + Tab 2 Content + +
+ +
+ + + Tab 1 Title + Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title + + Tab 1 content + Tab 2 Content + +
+ +
+ + + Tab 1 Title + Tab 2 Title + Tab 3 Title + Tab 4 Title + Tab 5 Title + Tab 6 Title Tab 1 content Tab 2 Content @@ -350,6 +485,7 @@ Tab 1 Title Tab 2 Title + Tab 3 Title Tab 1 content Tab 2 Content @@ -361,6 +497,51 @@ Tab 1 Title Tab 2 Title + Tab 3 Title + + Tab 1 content + Tab 2 Content + +
+
+ + +
+
tab position: bottom with border + icon-start + icon end closable
+ +
+ + + Tab 1 Title + Tab 2 Title + + Tab 1 content + Tab 2 Content + +
+ +
+ + + Tab 1 Title + Tab 2 Title + + Tab 1 content + Tab 2 Content + +
+ +
+ + + Tab 1 Title + Tab 2 Title Tab 1 content Tab 2 Content