How to label both sides of a mat-slide-toggle control in Angular/Material 8?
Asked Answered
S

3

5

I'm using mat-slide-toggle on a settings screen to show various "this or that" options, e.g.:

<div class="row">
    <div class="column">
        Automatically adjust display to screen
    </div>
    <div class="column">
        <mat-label>Off&nbsp;</mat-label>
        <mat-slide-toggle formControlName="autoLayout">On</mat-slide-toggle>
        <mat-label>&nbsp;On</mat-label>
    </div>
</div>

<div class="row">
    <div class="column">
        Choose preferred manual layout
    </div>
    <div class="column">                            
        Landscape&nbsp;<mat-slide-toggle formControlName="portrait"></mat-slide-toggle>&nbsp;Portrait
    </div>
</div>

Which looks like this:

Screenshot from above code snippet

Note that the "On" which is part of the mat-slide-toggle is styled slightly differently to the Off/On which are outside of the control.

Is there any way to replicate the internal label, on the left-hand side of the toggle AND the right-hand side, without having to do a load of CSS jiggery-pokery, which I've tried and failed to do already?

Stroud answered 2/10, 2019 at 14:57 Comment(4)
Slide toggles are just fancy checkboxes, which are essentially Booleans. But you're presenting a choice between landscape and portrait. In that layout, you'd be better off using a select. But if you have to use the slide toggle, I'd treat it as a way to opt into an alternate orientation. Which would mean changing the label to "Use portrait orientation", if the default orientation is landscape. Or vice versa. And you can add hint text below the the row to dynamically explain the current orientation, like: "The current orientation is [landscape/portrait]."Upsetting
It's a fair point for the Landscape/Portrait switch ( I might add "auto" later, which would of course, need a slider with a middle position!); but the "on/off" example is still valid I feel.Stroud
I think you're overthinking things, even with the automatically adjust display to screen setting. Again, the slide toggle is still just a checkbox. It's checked or it's not checked. The off and on text on either side just confuses things. Especially if you keep the "On" label, which results in seeing the word "on" twice. I know this is an old question, so none of this probably matters. And I respect your opinions. Good luck in the future.Upsetting
@BryanSullivan - "Especially if you keep the "On" label, which results in seeing the word "on" twice.": On that specific point, no! If I could style the left-hand-side the same as the right-hand-side, then I'd not put a second label there! So it would just be "Off [slider] On" As for overthinking? I disagree. Good UI should be crystal clear, and uncluttered. Yes, I could rephrase the statement(s) to make it a true/false option & therefore not need a label on the checkbox; but (particularly with choose orientation), I feel that makes it LESS clear.Stroud
A
9

Add class mat-slide-toggle-content (which is defined by angular material and applied to the label) to your secondary label and also append following three CSS rules to the label.

vertical-align: top;
display: inline-block;
line-height: 24px; // this is defined in .mat-slide-toggle
Ammoniate answered 2/10, 2019 at 15:47 Comment(0)
S
4

In your module:

import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatFormFieldModule  } from '@angular/material/form-field';
...
@NgModule({
  declarations: [...],
  imports: [
    ...
    MatSlideToggleModule,
    MatFormFieldModule 
  ],
  exports: []
})

In your html:

<div class="container">
  <div class="row ">
    ...
    <div class="col ">
        <mat-label ngClass="labelBeforeSlide">Off</mat-label>
        <mat-slide-toggle>On</mat-slide-toggle>
    </div>
    ...

In your css:

.labelBeforeSlide {
  vertical-align: top;
  line-height: 24px; 
  margin-right:0.5rem;
  margin-bottom:0.5rem;
}

Supervise answered 21/2, 2020 at 9:59 Comment(1)
This was very close for me but user interaction on Label click was missing. Essentially adding for="toggle-id" fixes that. I will leave the solution from git itself: github.com/angular/components/issues/…Acceptance
U
1

Here is a slight improvement on the original post, with a focus on A11Y.

Any text you put inside the Angular Material slide toggle's opening and closing tags is projected into a label element inside that component. So skip putting any text inside it and use an aria-labelledby attribute for the label instead.

You should also use <span> elements instead of <mat-label>. The <mat-label> doesn't do anything outside of the Angular Material form field component and it has no A11Y functionality. It's just an undefined HTML element with no semantics as used in the original post.

I also took some liberty with the class names and css. No more &nbsp; necessary. You can ignore those changes.

HTML

<div class="settings">
  <div class="row">
    <div class="label" id="autoLayoutLabel">
      Automatically adjust display to screen
    </div>
    <div class="control">
      <span>Off</span>
      <mat-slide-toggle
        formControlName="autoLayout"
        aria-labelledby="autoLayoutLabel"></mat-slide-toggle>
      <span>On</span>
    </div>
  </div>
  <div class="row">
    <div class="label" id="portraitLabel">Choose preferred manual layout</div>
    <div class="control">
      <span>Landscape</span>
      <mat-slide-toggle
        formControlName="portrait"
        aria-labelledby="portraitLabel"></mat-slide-toggle>
      <span>Portrait</span>
    </div>
  </div>
</div>

CSS

.settings {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.row {
  display: flex;
  padding: 1rem;
  border-top: 1px solid rgba(0, 0, 0, 0.12);
}

.row:last-of-type {
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}

.label {
  flex: 1;
}

.control {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
Upsetting answered 26/5, 2023 at 16:29 Comment(1)
This looks like a good answer - I'd definitely try it out; I have, however, since switched away from Angular to React - and honestly, the project that used this bit of layout is currently a tad dormant....! But thanks anyway!Stroud

© 2022 - 2024 — McMap. All rights reserved.