De Wet van As
De Wet van As

Reputation: 1000

How can I customize the label of an ion-select in Ionic 7?

I am using Ionic 7 and Angular (material) 14.

I want to display a required field indicator (*) in the field labels where applicable.

In Ionic 6, I achieved this by using adding span tag in the ion-label, with a class for styling, ex:

<ion-item>
  <ion-label position="fixed">Title<span class="required-field-indicator">*</span></ion-label>
  <ion-select formControlName="title">
    <ion-select-option *ngFor="let title of titles" value="{{title}}">{{title}}</ion-select-option>
  </ion-select>
</ion-item>

I could then change the styling of my indicator using CSS:

.required-field-indicator {
  color: var(--ion-color-tertiary);
  font-weight: bolder;
  padding: 2px;
}

My field would display as follows:

enter image description here

I've now upgraded to Ionic 7, and as per the documentation (https://ionicframework.com/docs/api/select), the ion-label no longer works with ion-input and ion-select. Instead, one should use the label and label-placement properties on the ion-select component as per example:

enter image description here

I've updated my code accordingly:

<ion-item>
  <ion-select label="Title" labelPlacement="fixed" formControlName="title" [required]="true">
    <ion-select-option *ngFor="let title of titles" value="{{title}}">{{title}}</ion-select-option>
  </ion-select>
</ion-item>

However, with this change, I can no longer add (unless I add it as character in the label property) or customize my required field indicator symbol.

enter image description here

How can I add a my indicator and style it in Ionic 7?

I have managed to do it using CSS on the ion-input component:

.required-indicator {
  .label-text::after {
    content: '*';
    transform: translate(-100%, 0);
    color: var(--ion-color-tertiary) !important;
    font-weight: bolder;
    padding: 2px;
  }
}

<ion-input label="First Name" labelPlacement="fixed" type="text" formControlName="firstName"
              class="required-indicator" [required]="true"></ion-input>

But this does not work on the ion-select. I have also tried using the shadow parts and creating a directive to append the indicator the DOM, but I can't access the label in any case. Please help!

Upvotes: 6

Views: 4726

Answers (3)

Maxime Lechevallier
Maxime Lechevallier

Reputation: 1196

Use the CSS Shadow Parts​ of the select component.

<ion-select class="required-field-indicator" ...
ion-select.required-field-indicator::part(label) {
    /* your style here */
}

Upvotes: 2

Emil
Emil

Reputation: 7256

There is currently no way to do this (Ionic 7.0.10), but it has been discussed as a feature request in the Github Repository for Ionic. Looks like they will add the label as a Shadow DOM Part, allowing you to style it in the same way you can style the placeholder and text, as shown in the answer by @Maxime.

Upvotes: 1

Ettore Amato
Ettore Amato

Reputation: 11

I was trying to accomplish the same thing and finally have come with a solution.

Since the label is in the shadow-root of the IonSelect, and there's no part attribute to expose it, there's no way to style it in the SCSS files but it can be done in typescript like this:

// For referencing all of the ion-select inside the form
@ViewChildren(IonSelect) ionSelects; 

ngAfterViewInit() {
   // This was for being sure of having all the ion-select loaded
   this.ionSelects.changes.subscribe(data => {
      // Creating the CSS rules we're gonna apply inside the shadow-root
      const sheet = new CSSStyleSheet();
      sheet.replaceSync(`.label-text::after {
         content: ' *';
         transform: translate(-100%, 0);
         color: var(--ion-color-secondary) !important;
         display: var(--ion-label-display); // This is necessary to show 
         // and hide the asterisk
         font-weight: bolder;
         padding: 2px;
      }`)
           
      const arrIonSelect = data.toArray(); // From Queryselector 
      // to Array of IonSelect
      arrIonSelect.forEach((isel) => {
         // Storing the current CSS rules used by the shadow-root
         const elemStyleSheets = 
            isel.el.shadowRoot.adoptedStyleSheets;
         // Merging the rules
         isel.el.shadowRoot.adoptedStyleSheets = 
            [...elemStyleSheets, sheet];
      });
   });
}

Finally in the html we'll bind the style attribute to the required 'condition' :

<ion-select  
[style.--ion-label-display]="form.get('title')?.errors?.required ? 'initial' : 'none'"
label="Title" labelPlacement="stacked" formControlName="title">
   <ion-select-option *ngFor="let title of titles" value="{{title}}">{{title}}</ion-select-option>
</ion-select>

I expect them to change something in the future, but for now I hope it helps, it did for me.

Upvotes: 1

Related Questions