Curved cornered menu

Hi guys,
Is it possible to apply ‘border-top-right-radius’ to ion-content inside ion-menu?
I have tried to change ‘border-top-right-radius’ to ion-content inside ion-menu but it not worked.

there are class under shadow-root called ‘menu-inner’. If I apply ‘border-top-right-radius’ inside this class, it works as i want. But problem is I am unable to change this from project.
Please see the picture attached for details

Please help

As you can’t edit the Shadow Dom by css directly, here is how i use a Directive to edit it:

This is the Directive:

import {Directive, ElementRef, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import {InjectStylesService} from '../services/inject-styles/inject-styles.service';
import {InjectStyle} from '../services/inject-styles/classes/inject-style';

@Directive({
  selector: '[styles]'
})
export class InjectStylesDirective implements OnInit, OnChanges {

  @Input()
  styles: InjectStyle | InjectStyle[];

  constructor(private elementRef: ElementRef,
              private injectStylesService: InjectStylesService) {
  }


  ngOnInit() {
    this.perform(this.styles);
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes && changes.styles && !changes.styles.isFirstChange() && changes.styles.previousValue !== changes.styles.currentValue) {
      this.perform(changes.styles.currentValue);
    }
  }

  private perform(myStyles: InjectStyle | InjectStyle[]) {
    this.injectStylesService.inject(this.elementRef.nativeElement, myStyles);
  }
}

This is the Service:

import {Injectable} from '@angular/core';
import {InjectStyle} from './classes/inject-style';

@Injectable({
  providedIn: 'root'
})
export class InjectStylesService {

  constructor() {
  }

  inject(element: HTMLElement, myStyles: InjectStyle | InjectStyle[]) {
    const root = element.shadowRoot;
    if (root && myStyles) {
      const styleElements = root.querySelectorAll('style');

      const styles = Array.isArray(myStyles) ? myStyles : [myStyles];

      for (const style of styles) {
        style.style = style.insertBeforeSelector + ' {' + style.style + '}';
        if (!Array.from(styleElements).some(el => el.innerHTML === style.style)) {
          this.removeOld(style, styleElements);
          const newStyleTag = document.createElement('style');
          newStyleTag.innerHTML = style.style;
          root.insertBefore(newStyleTag, root.querySelector(style.insertBeforeSelector));
        }
      }
    }
  }

  private removeOld(style: InjectStyle, styleElements: NodeListOf<HTMLStyleElement>) {
    styleElements.forEach(styleElement => {
      if (styleElement.innerHTML.startsWith(style.insertBeforeSelector)) {
        styleElement.remove();
      }
    });
  }
}

This is the Class

export interface InjectStyle {
  insertBeforeSelector: string;
  style: string;
}

You can combine these Directive + Service of course. I create a Service, because i use the same functionality outside of the directive too.

You can then use it in your case like this:

<ion-menu [styles]="menuStyles">...</ion-menu>

while menuStyles is initialized as:

menuStyles: InjectStyle = {
  insertBeforeSelector: '.menu-inner', // the class you want to edit
  style: 'border-top-right-radius: 50px;' // the styles as string
}

If you have any Problems with this, just hit me up

1 Like

Thank you for your rply
i did according to your suggestion but not working

it is my directive file

import { Directive, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { InjectStylesServiceService } from '../services/InjectStylesService/inject-styles-service.service';
import { InjectStyle } from '../classes/inject-style';

@Directive({
  selector: '[appInjectStylesDirective]'
})
export class InjectStylesDirectiveDirective implements OnInit, OnChanges {

  @Input()
  styles: InjectStyle | InjectStyle[];

  constructor(
    private elementRef: ElementRef,
    private injectStylesService: InjectStylesServiceService
  ) { }

  ngOnInit() {
    this.perform(this.styles);
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes && changes.styles && !changes.styles.isFirstChange() && changes.styles.previousValue !== changes.styles.currentValue) {
      this.perform(changes.styles.currentValue);
    }
  }

  private perform(myStyles: InjectStyle | InjectStyle[]) {
    this.injectStylesService.inject(this.elementRef.nativeElement, myStyles);
  }

}

it is my service

import { Injectable } from '@angular/core';
import { InjectStyle } from '../../classes/inject-style';

@Injectable({
  providedIn: 'root'
})
export class InjectStylesServiceService {

  constructor() { }

  inject(element: HTMLElement, myStyles: InjectStyle | InjectStyle[]) {
    const root = element.shadowRoot;
    if (root && myStyles) {
      const styleElements = root.querySelectorAll('style');

      const styles = Array.isArray(myStyles) ? myStyles : [myStyles];

      for (const style of styles) {
        style.style = style.insertBeforeSelector + ' {' + style.style + '}';
        if (!Array.from(styleElements).some(el => el.innerHTML === style.style)) {
          this.removeOld(style, styleElements);
          const newStyleTag = document.createElement('style');
          newStyleTag.innerHTML = style.style;
          root.insertBefore(newStyleTag, root.querySelector(style.insertBeforeSelector));
        }
      }
    }
  }

  private removeOld(style: InjectStyle, styleElements: NodeListOf<HTMLStyleElement>) {
    styleElements.forEach(styleElement => {
      if (styleElement.innerHTML.startsWith(style.insertBeforeSelector)) {
        styleElement.remove();
      }
    });
  }
}

this is my class

export class InjectStyle {
    insertBeforeSelector: string;
    style: string;
}

it is my app.compoment.html

<ion-app>
  <ion-split-pane contentId="main-content">
    <ion-menu contentId="main-content" type="overlay" [styles]="menuStyles">
      <ion-content>
        <div>
          <ion-list id="inbox-list">
            <ion-list-header>Inbox</ion-list-header>
            <ion-note>hi@ionicframework.com</ion-note>

            <ion-menu-toggle auto-hide="false" *ngFor="let p of appPages; let i = index">
              <ion-item (click)="selectedIndex = i" routerDirection="root" [routerLink]="[p.url]" lines="none"
                detail="false" [class.selected]="selectedIndex == i">
                <ion-icon slot="start" src='../assets/icons/{{p.icon}}.svg'></ion-icon>
                <ion-label>{{ p.title }}</ion-label>
              </ion-item>
            </ion-menu-toggle>
          </ion-list>
        </div>
      </ion-content>
    </ion-menu>
    <ion-router-outlet id="main-content"></ion-router-outlet>
  </ion-split-pane>
</ion-app>

this is my app.componen.ts

import { Component, OnInit } from '@angular/core';

import { Platform } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { InjectStyle } from './classes/inject-style';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss']
})
export class AppComponent implements OnInit {
  public selectedIndex = 0;
  public appPages = [
    {
      title: 'Product',
      url: '/folder/Inbox',
      icon: 'product'
    },
    {
      title: 'History',
      url: '/folder/Outbox',
      icon: 'history'
    },
    {
      title: 'Cart',
      url: '/folder/Favorites',
      icon: 'heart'
    },
    {
      title: 'Gifts',
      url: '/folder/Archived',
      icon: 'archive'
    },
    {
      title: 'Settings',
      url: '/folder/Trash',
      icon: 'trash'
    },
    {
      title: 'Help',
      url: '/folder/Spam',
      icon: 'warning'
    }
  ];

  menuStyles: InjectStyle = {
    insertBeforeSelector: '.menu-inner', // the class you want to edit
    style: 'border-top-right-radius: 50px!important;' // the styles as string
  };

  constructor(
    private platform: Platform,
    private splashScreen: SplashScreen,
    private statusBar: StatusBar
  ) {
    this.initializeApp();
  }

  initializeApp() {
    this.platform.ready().then(() => {
      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }

  ngOnInit() {
    const path = window.location.pathname.split('folder/')[1];
    if (path !== undefined) {
      this.selectedIndex = this.appPages.findIndex(page => page.title.toLowerCase() === path.toLowerCase());
    }
  }
}

If you inspect the Menu, are the styles applied?

Unsure, but i think you need a Space before the !important too, so:

menuStyles: InjectStyle = {
    insertBeforeSelector: '.menu-inner', // the class you want to edit
    style: 'border-top-right-radius: 50px !important;' // the styles as string
  };

No, the styles are not applying. i have inspect the menu
and I have tried with !important

here is my code

menuStyles: InjectStyle = {
    insertBeforeSelector: '.menu-inner', // the class you want to edit
    style: 'border-top-right-radius: 50px !important;' // the styles as string
  };

Try debugging through the code and check where it fails