4

I wanted to modify Angular Material's Tab Component to be displayed vertically. So I went here (Tabs) and played with the CSS. I managed to display the tabs vertically. with the following CSS:

.mat-tab-group {
    display: flex;
    flex-direction: row!important;
}
.mat-tab-labels {
    display: flex;
    flex-direction: column!important;
}

But the mat-ink-bar stays at the bottom as expected: vertical tabs

How do I rotate the bar to display it vertically and positioned at the right side of the tab labels? Also hoping that the bar's transition can also be retained.

I'm thinking that the bar can be rotated clock-wise by 90 degrees and positioned properly on the right side. The width of the bar can be set equal to the height of the tabs too.

Alex Pappas
  • 2,377
  • 3
  • 24
  • 48
  • Does this answer your question? [Vertical tabs with Angular Material](https://stackoverflow.com/questions/49809702/vertical-tabs-with-angular-material) – qubits May 19 '20 at 11:13

2 Answers2

1

Nobody seems to have provided code samples so I will since I figured it out. Thanks to the other answer for the insight.

Here is how I am doing it.

Put this in some SCSS somewhere, either globally or wherever you need it (converting to basic CSS I will leave up to you if you need it that way):

mat-tab-group[vertical] {
  flex-direction: row;

  ::ng-deep mat-tab-header {
    flex-direction: column;
    border-bottom: 0px solid transparent;
    border-right: 1px solid rgba(0, 0, 0, 0.12);

    .mat-tab-label-container {
      flex-direction: column;

      .mat-tab-labels {
        flex-direction: column;
      }

      mat-ink-bar {
        left: initial !important;
        bottom: initial;
        right: 0;
        width: 2px !important;
        height: initial;
      }
    }
  }

  ::ng-deep .mat-tab-body-wrapper {
    flex-direction: column;
    width: 100%;
  }
}

:host-context(.dark) mat-tab-group[vertical] ::ng-deep mat-tab-header {
  border-right: 1px solid rgba(255, 255, 255, 0.12);
}

Now make the following changes to your component TS. You might want to put this in your main app component TS if you will use vertical tabs frequently. Otherwise add it to each relevant component.

First implement the DoCheck interface and add the following function:

ngDoCheck() {
  document.querySelectorAll("mat-tab-group[vertical]").forEach((verticalTabGroup: HTMLElement) => {
    let inkBar: HTMLElement = verticalTabGroup.querySelector("mat-ink-bar");
    if (!inkBar) {
      return;
    }
    let active: HTMLElement = verticalTabGroup.querySelector(".mat-tab-label-active");
    if (!active) {
      return;
    }
    inkBar.style.top = `${active.offsetTop}px`;
    inkBar.style.height = `${active.offsetHeight}px`;
  });
}

Maybe there's a better way to do this in angular, I'm afraid I've got an old school vanilla background and I'm still learning,

One thing missing is the body still scrolls horizontally when you change tabs. This seems to be done using JS by brute forcing CSS transform styles so it can't be adjusted without modifying the original mat-tab-group source.

Keep in mind I only did basic testing with a simple tab group. I am not sure if the pagination arrows will work properly with this. I'll leave that as an exercise for the developer who needs it.

Another exercise for anyone curious: Perhaps it may be possible to rotate the entire tab group with a CSS transform, then rotate the tab labels and tab bodies back to turn the whole thing vertical. this would allow the ink bar and body transitions to work as-is, in theory. But it's probably overkill.

user169771
  • 1,962
  • 2
  • 13
  • 11
0

I think

<mat-ink-bar class="mat-ink-bar" style="visibility: visible; left: 160px; width: 160px;"></mat-ink-bar>

is the element that you need to modify. instead of left positioning you need to have top bottom positioning as per your image above.This can not be done only with css as the left position is dynamically updated whenever you Tap or click upon the tab. and in css

.mat-ink-bar {
position: absolute;
bottom: 0;
height: 2px;
transition: .5s cubic-bezier(.35,0,.25,1);

} instead of height take width : 2px, and height shall be the height of the .mat-tab-label.

vssadineni
  • 454
  • 4
  • 11
  • Im no css expert but I believe there's a hack for this to rotate the ink bar clockwise by 90 degrees and position properly on the right side. Yes we can manually change the width of the bar according to the height of the tabs (assuming they're not dynamic). – Alex Pappas Nov 19 '18 at 06:07
  • opting for hack is not advisable as you want to retain the animation as well. There will be an option that can change the direction in some Method or option trigger form in TS or JS that is handling this. One who developed this framework might have thought of this requirement right. – vssadineni Nov 19 '18 at 06:12
  • probably you could refer to this hope it might help you. https://stackoverflow.com/questions/49809702/vertical-tabs-with-angular-material – vssadineni Nov 19 '18 at 06:19
  • Actually already went through these links. Thank you very much. :) – Alex Pappas Nov 19 '18 at 06:28
  • ** transform: rotate(90deg); transform-origin: right; ** will rotate the element vertically and place it to the end of theelement i.e, right. :), but I am unable to imagine how the animation would be.Hope you will be able to manage the animation part. Ya do remember the width and left properties in inline style. – vssadineni Nov 19 '18 at 06:32