CSS class styles not applied to ion-input native element using getInputElement and Renderer2

I cannot seem to get any CSS classes’ styles applied to an input element in ion-input. Here’s a simple example of what I am trying…

home.page.ts

<ion-content>
  <ion-item>
    <ion-input #ioninput placeholder="Ion Input" ></ion-input>
  </ion-item>

  <input #normalinput placeholder="Normal input" type="text">
</ion-content>

home.page.scss

.aqua-marine{
  background-color: aquamarine;
}

home.page.ts

import { Component, AfterViewInit, ElementRef, ViewChild, Renderer2 } from "@angular/core";
import { IonInput } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements AfterViewInit {
  @ViewChild("ioninput") ionInputExample: IonInput;
  @ViewChild('normalinput', { read: ElementRef }) normalInputExample: ElementRef;

  constructor(private renderer: Renderer2) { }

  ngAfterViewInit() {
    this.ionInputExample.getInputElement().then(nativeInputInsideIonInput => {
      this.renderer.addClass(nativeInputInsideIonInput, "aqua-marine");
      console.log('ion-input: ', nativeInputInsideIonInput);      
    });

    const ni = this.normalInputExample.nativeElement;
    this.renderer.addClass(ni, "aqua-marine");
    console.log('ni: ', ni);
  }
}

The console logs are showing that each class has been added to each element but only the native input is applying the class’s styles. As the example shows I can successfully use Renderer2’s setStyle method but not the addClass.

I’m stumped. Any thoughts or suggestions are appreciated.

<ion-input class="aqua"></ion-input>
ion-input.aqua {
  --background: aqua;
}

Thank you for the reply.

I should have used a styling example that was not already supported by the ion-input component.

I am more interested in understanding why Renderer2’s addClass method does not affect the style of the ion-input’s input element.

I’m not so sure about that, because the example that you did choose shines light upon (what I think, at least) is a really important point: the role of encapsulation in libraries. There are aspects of Ionic components that are really easy to customize, and then there are those that aren’t. I choose to look at this distinction not as arbitrary, but as an informed and deliberate design choice by the Ionic team (which I may need to again point out that I am totally unaffiliated with).

If everything is public, then frameworks have zero room to evolve. Every change becomes a breaking change.

So if I were in your shoes, I would forget about trying to hack my way into Ionic internals, and instead work on making my case for exposing as easily customizable whatever property it is that I was really trying to change. Then I would make a feature request here laying out that case.

You bring up some great points that I completely agree with.

Full disclosure, I stumbled on a question on Stack Overflow that I thought would be interesting to look into. This ultimately led me to post this question. I am trying to understand if the Renderer2.addClass behavior, when used on the ion-input’s native input element, is by design or is it a bug with the component. I think its a possible bug since at least one (I need to test more of them) of Renderer2 methods do affect the input element as defined in the API. I wanted to make sure I am not missing anything which is why I brought the question to the forum before I bring it up to the Ionic team.

I agree that digging into the Ionic internals is a bad idea. However, since ion-input provides a method which exposes the native element in getInputElement(), it seems reasonable to me to expect that all of Renderer2’s rendering capabilities will function on the input element as described in the Renderer2 API.

I’m not sure I can answer your direct question, but I can say this. You are fighting a couple of foes here.

First up is Angular’s ViewEncapsulation, which I suspect is the primary boulder in the middle of your road. So you’ll need to set that to something other than the default of Emulated - in my brief testing either ShadowDom or None sufficed.

Secondly, you’re losing a specificity battle with the styles defined by Ionic for this component, so I had to alter your CSS accordingly:

.aqua-marine, input.native-input.aqua-marine {
  background-color: aquamarine;
}

Just to reiterate for future viewers: I’m emphatically not recommending actually doing any of this in app code.

1 Like