Intégration web angularforall.com

- Kendo UI Telerik : composants UI pour Angular

Kendo Ui Telerik Angular Composants Ui Enterprise
Kendo UI Telerik : composants UI pour Angular

Maîtrisez Kendo UI for Angular : Grid virtualisé, Charts, DatePicker, Dialogs et thèmes. Guide complet avec 15+ exemples pour applications enterprise.

Présentation de Kendo UI for Angular

Kendo UI for Angular est la librairie de composants UI professionnelle développée par Progress/Telerik. Conçue exclusivement pour Angular (sans jQuery), elle propose plus de 100 composants — des tableaux de données complexes aux graphiques interactifs, en passant par les calendriers, éditeurs de texte riche et schedulers d'entreprise.

Contrairement à beaucoup de librairies open source, Kendo UI est optimisée pour les cas d'usage enterprise : grands volumes de données, virtualisation du scroll, internationalisation complète (i18n/l10n), accessibilité WCAG 2.1 AA et support professionnel garanti. C'est l'un des choix de référence pour les applications back-office et dashboards Angular complexes.

Architecture de la librairie

Kendo UI for Angular est découpée en packages npm indépendants. Vous n'importez que ce dont vous avez besoin :

Package Composants inclus
@progress/kendo-angular-grid Grid, TreeList, Spreadsheet
@progress/kendo-angular-inputs TextBox, NumericTextBox, MaskedTextBox, Slider, Switch
@progress/kendo-angular-dateinputs DatePicker, TimePicker, DateTimePicker, DateRangePicker, Calendar
@progress/kendo-angular-charts Bar, Line, Area, Pie, Donut, Scatter, Bubble, Heatmap
@progress/kendo-angular-dialogs Dialog, Window, Notification
@progress/kendo-angular-dropdowns DropDownList, AutoComplete, ComboBox, MultiSelect
@progress/kendo-angular-buttons Button, ButtonGroup, ToolBar, SplitButton, DropDownButton
@progress/kendo-angular-layout TabStrip, Splitter, Stepper, ExpansionPanel, Drawer
@progress/kendo-angular-editor Éditeur de texte riche (WYSIWYG)
@progress/kendo-angular-scheduler Scheduler (agenda, semaine, mois, timeline)
Licence : Kendo UI for Angular est une librairie commerciale. Un essai gratuit de 30 jours est disponible. Une édition open source partielle (Kendo UI Free Components) propose un sous-ensemble de composants sous licence MIT.

Installation et configuration

Kendo UI for Angular propose un schématic Angular CLI pour automatiser l'installation. C'est la méthode recommandée car elle configure automatiquement les providers, les thèmes et les animations.

Installation via schématic (méthode recommandée)

# Installation automatique avec configuration complète
ng add @progress/kendo-angular-grid

# Ou installer plusieurs packages à la fois
npm install --save @progress/kendo-angular-grid \
  @progress/kendo-angular-inputs \
  @progress/kendo-angular-dateinputs \
  @progress/kendo-angular-buttons \
  @progress/kendo-angular-dropdowns \
  @progress/kendo-angular-dialogs \
  @progress/kendo-theme-default

Configurer le thème CSS

Kendo UI utilise ses propres fichiers CSS. Ajoutez le thème dans angular.json sous la section styles :

// angular.json — configurer le thème Kendo
{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "options": {
            "styles": [
              // Thème par défaut Kendo (choisir UN seul thème)
              "node_modules/@progress/kendo-theme-default/dist/all.css",
              // OU thème Bootstrap (si vous utilisez Bootstrap)
              // "node_modules/@progress/kendo-theme-bootstrap/dist/all.css",
              // OU thème Material
              // "node_modules/@progress/kendo-theme-material/dist/all.css",
              "src/styles.css"
            ]
          }
        }
      }
    }
  }
}

Configuration des providers dans app.config.ts (Angular Standalone)

// src/app/app.config.ts — configuration globale Angular 17+
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideAnimations } from '@angular/platform-browser/animations';
import { IntlModule } from '@progress/kendo-angular-intl';
// Locale française pour les formats de dates et nombres
import '@progress/kendo-angular-intl/locales/fr/all';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    // Obligatoire pour les animations Kendo (dialogs, notifications)
    provideAnimations(),
  ],
};

Vérification de l'installation

// src/app/app.component.ts — test rapide
import { Component } from '@angular/core';
import { ButtonsModule } from '@progress/kendo-angular-buttons';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ButtonsModule],
  template: `
    <!-- Si le bouton Kendo s'affiche, l'installation est correcte -->
    <button kendoButton themeColor="primary">
      Kendo UI fonctionne !
    </button>
  `,
})
export class AppComponent {}
Si vous voyez une erreur de licence au démarrage, créez un fichier kendo-ui-license.txt à la racine du projet avec votre clé de licence, ou lancez npx kendo-ui-license activate avec votre compte Telerik.

Kendo Grid : tableau de données avancé

Le Kendo Grid est le composant phare de la librairie. Il offre tri, filtrage, pagination, regroupement, sélection, édition inline, virtualisation du scroll et export Excel/PDF — tout out-of-the-box. C'est le composant qui justifie souvent à lui seul l'achat d'une licence.

Grid de base avec tri et pagination

// products-grid.component.ts
import { Component, OnInit } from '@angular/core';
import { GridModule } from '@progress/kendo-angular-grid';
import { SortDescriptor, orderBy } from '@progress/kendo-data-query';

interface Product {
  id: number;
  name: string;
  category: string;
  price: number;
  stock: number;
  active: boolean;
}

@Component({
  selector: 'app-products-grid',
  standalone: true,
  imports: [GridModule],
  template: `
    <kendo-grid
      [data]="gridData"
      [pageSize]="pageSize"
      [skip]="skip"
      [pageable]="true"
      [sortable]="true"
      [sort]="sort"
      (sortChange)="sortChange($event)"
      (pageChange)="pageChange($event)"
      style="height: 500px"
    >
      <!-- Colonne ID non redimensionnable -->
      <kendo-grid-column field="id" title="ID" [width]="60" [resizable]="false"></kendo-grid-column>

      <!-- Colonne nom avec lien cliquable -->
      <kendo-grid-column field="name" title="Produit">
        <ng-template kendoGridCellTemplate let-dataItem>
          <a [routerLink]="['/products', dataItem.id]">{{ dataItem.name }}</a>
        </ng-template>
      </kendo-grid-column>

      <!-- Colonne catégorie -->
      <kendo-grid-column field="category" title="Catégorie" [width]="140"></kendo-grid-column>

      <!-- Colonne prix avec formatage euro -->
      <kendo-grid-column field="price" title="Prix" format="{0:c2}" [width]="120"></kendo-grid-column>

      <!-- Colonne stock avec indicateur visuel -->
      <kendo-grid-column field="stock" title="Stock" [width]="100">
        <ng-template kendoGridCellTemplate let-dataItem>
          <span [class.text-danger]="dataItem.stock === 0"
                [class.text-warning]="dataItem.stock > 0 && dataItem.stock <= 5"
                [class.text-success]="dataItem.stock > 5">
            {{ dataItem.stock === 0 ? 'Rupture' : dataItem.stock }}
          </span>
        </ng-template>
      </kendo-grid-column>

      <!-- Colonne statut avec badge -->
      <kendo-grid-column field="active" title="Statut" [width]="100">
        <ng-template kendoGridCellTemplate let-dataItem>
          <span class="badge" [class.bg-success]="dataItem.active" [class.bg-secondary]="!dataItem.active">
            {{ dataItem.active ? 'Actif' : 'Inactif' }}
          </span>
        </ng-template>
      </kendo-grid-column>
    </kendo-grid>
  `,
})
export class ProductsGridComponent implements OnInit {
  products: Product[] = [];
  gridData: Product[] = [];
  sort: SortDescriptor[] = [];
  pageSize = 10;
  skip = 0;

  ngOnInit(): void {
    // Simulation de 50 produits
    this.products = Array.from({ length: 50 }, (_, i) => ({
      id: i + 1,
      name: `Produit ${i + 1}`,
      category: ['Électronique', 'Mode', 'Maison', 'Sport'][i % 4],
      price: Math.round(Math.random() * 500 + 10),
      stock: Math.floor(Math.random() * 50),
      active: Math.random() > 0.2,
    }));
    this.loadData();
  }

  sortChange(sort: SortDescriptor[]): void {
    this.sort = sort;
    this.loadData();
  }

  pageChange({ skip }: { skip: number }): void {
    this.skip = skip;
    this.loadData();
  }

  private loadData(): void {
    // Tri côté client via kendo-data-query
    const sorted = orderBy(this.products, this.sort);
    this.gridData = sorted.slice(this.skip, this.skip + this.pageSize);
  }
}

Grid avec filtrage et édition inline

// editable-grid.component.ts — édition directe dans la grille
import { Component } from '@angular/core';
import { GridModule, EditService, CellCloseEvent } from '@progress/kendo-angular-grid';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';

@Component({
  selector: 'app-editable-grid',
  standalone: true,
  imports: [GridModule, ReactiveFormsModule],
  template: `
    <kendo-grid
      [data]="employees"
      [filterable]="'row'"
      [groupable]="true"
      (cellClick)="cellClickHandler($event)"
      (cellClose)="cellCloseHandler($event)"
    >
      <!-- Filtre par ligne activé sur chaque colonne -->
      <kendo-grid-column field="firstName" title="Prénom" [editable]="true"></kendo-grid-column>
      <kendo-grid-column field="lastName"  title="Nom"    [editable]="true"></kendo-grid-column>
      <kendo-grid-column field="salary"    title="Salaire" format="{0:n0} €" [editable]="true"></kendo-grid-column>

      <!-- Colonne d'actions -->
      <kendo-grid-command-column title="Actions" [width]="150">
        <ng-template kendoGridCellTemplate let-isNew="isNew">
          <button kendoGridEditCommand themeColor="primary" size="small">Éditer</button>
          <button kendoGridSaveCommand themeColor="success" size="small">Sauvegarder</button>
          <button kendoGridCancelCommand size="small">Annuler</button>
          <button kendoGridRemoveCommand themeColor="error" size="small">Supprimer</button>
        </ng-template>
      </kendo-grid-command-column>
    </kendo-grid>
  `,
})
export class EditableGridComponent {
  employees = [
    { id: 1, firstName: 'Marie', lastName: 'Dupont', salary: 42000 },
    { id: 2, firstName: 'Pierre', lastName: 'Martin', salary: 55000 },
    { id: 3, firstName: 'Sophie', lastName: 'Bernard', salary: 38000 },
  ];

  cellClickHandler({ sender, rowIndex, columnIndex, dataItem, isEdited }: any): void {
    if (!isEdited) {
      sender.editCell(rowIndex, columnIndex, this.createFormGroup(dataItem));
    }
  }

  cellCloseHandler(args: CellCloseEvent): void {
    const { formGroup, dataItem } = args;
    if (!formGroup.dirty) return;
    if (formGroup.valid) {
      Object.assign(dataItem, formGroup.value);
    }
  }

  createFormGroup(dataItem: any): FormGroup {
    return new FormGroup({
      firstName: new FormControl(dataItem.firstName, Validators.required),
      lastName:  new FormControl(dataItem.lastName,  Validators.required),
      salary:    new FormControl(dataItem.salary,    [Validators.required, Validators.min(0)]),
    });
  }
}
Virtual Scrolling : Pour les tableaux avec des milliers de lignes, activez la virtualisation avec [scrollable]="'virtual'" et [rowHeight]="36". Kendo Grid ne rend que les lignes visibles, garantissant des performances constantes quelle que soit la taille des données.

Composants de formulaires

Kendo UI propose une suite complète de composants de formulaires qui s'intègrent nativement avec Angular Reactive Forms et Template-Driven Forms. Chaque composant implémente ControlValueAccessor et est compatible avec FormControl.

NumericTextBox — saisie de nombres

// order-form.component.ts
import { Component } from '@angular/core';
import { InputsModule } from '@progress/kendo-angular-inputs';
import { LabelModule }  from '@progress/kendo-angular-label';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';

@Component({
  selector: 'app-order-form',
  standalone: true,
  imports: [InputsModule, LabelModule, ReactiveFormsModule],
  template: `
    <form [formGroup]="orderForm" (ngSubmit)="onSubmit()">
      <div class="row g-3">

        <!-- Quantité avec contrôles +/- -->
        <div class="col-md-6">
          <kendo-label text="Quantité" [for]="qty"></kendo-label>
          <kendo-numerictextbox
            #qty
            formControlName="quantity"
            [min]="1"
            [max]="1000"
            [step]="1"
            [format]="'n0'"
            placeholder="Ex: 10"
          ></kendo-numerictextbox>
        </div>

        <!-- Prix unitaire avec format monétaire -->
        <div class="col-md-6">
          <kendo-label text="Prix unitaire (€)" [for]="price"></kendo-label>
          <kendo-numerictextbox
            #price
            formControlName="unitPrice"
            [min]="0.01"
            [step]="0.01"
            [format]="'c2'"
            [decimals]="2"
          ></kendo-numerictextbox>
        </div>

        <!-- Total calculé (lecture seule) -->
        <div class="col-12">
          <div class="alert alert-info">
            <strong>Total :</strong>
            {{ (orderForm.value.quantity * orderForm.value.unitPrice) | number:'1.2-2' }} €
          </div>
        </div>

        <div class="col-12">
          <button kendoButton type="submit" themeColor="primary" [disabled]="orderForm.invalid">
            Valider la commande
          </button>
        </div>
      </div>
    </form>
  `,
})
export class OrderFormComponent {
  orderForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.orderForm = this.fb.group({
      quantity:  [1,    [Validators.required, Validators.min(1), Validators.max(1000)]],
      unitPrice: [9.99, [Validators.required, Validators.min(0.01)]],
    });
  }

  onSubmit(): void {
    if (this.orderForm.valid) {
      console.log('Commande soumise :', this.orderForm.value);
    }
  }
}

DatePicker et DateRangePicker

// reservation-form.component.ts
import { Component } from '@angular/core';
import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
import { LabelModule }      from '@progress/kendo-angular-label';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';

@Component({
  selector: 'app-reservation-form',
  standalone: true,
  imports: [DateInputsModule, LabelModule, ReactiveFormsModule],
  template: `
    <form [formGroup]="reservationForm" class="row g-3">

      <!-- DatePicker simple avec localisation française -->
      <div class="col-md-6">
        <kendo-label text="Date d'arrivée" [for]="checkin"></kendo-label>
        <kendo-datepicker
          #checkin
          formControlName="checkIn"
          format="dd/MM/yyyy"
          [min]="today"
          placeholder="JJ/MM/AAAA"
        ></kendo-datepicker>
      </div>

      <!-- DateRangePicker pour sélectionner une période -->
      <div class="col-12">
        <kendo-label text="Période de séjour"></kendo-label>
        <kendo-daterange>
          <kendo-dateinput kendoDateRangeStartInput formControlName="startDate"
            format="dd/MM/yyyy" placeholder="Début"></kendo-dateinput>
          <kendo-dateinput kendoDateRangeEndInput   formControlName="endDate"
            format="dd/MM/yyyy" placeholder="Fin"></kendo-dateinput>
          <kendo-daterange-popup></kendo-daterange-popup>
        </kendo-daterange>
      </div>

    </form>
  `,
})
export class ReservationFormComponent {
  today = new Date();

  reservationForm = this.fb.group({
    checkIn:   [null, Validators.required],
    startDate: [null, Validators.required],
    endDate:   [null, Validators.required],
  });

  constructor(private fb: FormBuilder) {}
}

DropDownList et MultiSelect

// tag-selector.component.ts
import { Component } from '@angular/core';
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
import { FormControl, ReactiveFormsModule } from '@angular/forms';

interface Tag {
  id: number;
  text: string;
  color: string;
}

@Component({
  selector: 'app-tag-selector',
  standalone: true,
  imports: [DropDownsModule, ReactiveFormsModule],
  template: `
    <div class="row g-3">

      <!-- DropDownList simple avec template personnalisé -->
      <div class="col-md-6">
        <label class="form-label fw-bold">Priorité</label>
        <kendo-dropdownlist
          [data]="priorities"
          textField="text"
          valueField="id"
          [formControl]="selectedPriority"
          [defaultItem]="{ id: null, text: 'Sélectionner...' }"
        >
          <!-- Template personnalisé pour chaque option -->
          <ng-template kendoDropDownListItemTemplate let-dataItem>
            <span class="badge me-2" [style.background-color]="dataItem.color"> </span>
            {{ dataItem.text }}
          </ng-template>
        </kendo-dropdownlist>
      </div>

      <!-- MultiSelect avec filtre de recherche intégré -->
      <div class="col-md-6">
        <label class="form-label fw-bold">Tags (multi-sélection)</label>
        <kendo-multiselect
          [data]="availableTags"
          textField="text"
          valueField="id"
          [formControl]="selectedTags"
          [filterable]="true"
          (filterChange)="filterTags($event)"
          placeholder="Rechercher des tags..."
        ></kendo-multiselect>
      </div>

    </div>

    <div class="mt-3">
      <p><strong>Priorité sélectionnée :</strong> {{ selectedPriority.value | json }}</p>
      <p><strong>Tags sélectionnés :</strong> {{ selectedTags.value?.length }} tag(s)</p>
    </div>
  `,
})
export class TagSelectorComponent {
  priorities = [
    { id: 1, text: 'Critique', color: '#ef4444' },
    { id: 2, text: 'Haute',    color: '#f97316' },
    { id: 3, text: 'Normale',  color: '#3b82f6' },
    { id: 4, text: 'Basse',    color: '#22c55e' },
  ];

  allTags: Tag[] = [
    { id: 1, text: 'Angular', color: '#dd0031' },
    { id: 2, text: 'TypeScript', color: '#3178c6' },
    { id: 3, text: 'RxJS', color: '#b7178c' },
    { id: 4, text: 'NgRx', color: '#ba2bd2' },
    { id: 5, text: 'Kendo UI', color: '#ff6900' },
  ];

  availableTags = [...this.allTags];
  selectedPriority = new FormControl(null);
  selectedTags     = new FormControl([]);

  filterTags(filterValue: string): void {
    this.availableTags = this.allTags.filter(t =>
      t.text.toLowerCase().includes(filterValue.toLowerCase())
    );
  }
}

Kendo Charts : visualisation de données

Kendo Charts offre une gamme complète de graphiques vectoriels (SVG) optimisés pour les dashboards Angular : barres, lignes, secteurs, donut, sparklines, heatmaps. Tous sont responsives, animés et accessibles.

Bar Chart avec données dynamiques

// sales-chart.component.ts
import { Component, OnInit } from '@angular/core';
import { ChartsModule } from '@progress/kendo-angular-charts';

interface MonthlySales {
  month: string;
  revenue: number;
  target: number;
}

@Component({
  selector: 'app-sales-chart',
  standalone: true,
  imports: [ChartsModule],
  template: `
    <kendo-chart style="height: 400px">
      <!-- Titre du graphique -->
      <kendo-chart-title text="Chiffre d'affaires mensuel 2026"></kendo-chart-title>

      <!-- Légende positionnée en bas -->
      <kendo-chart-legend position="bottom"></kendo-chart-legend>

      <!-- Axe des catégories (mois) -->
      <kendo-chart-category-axis>
        <kendo-chart-category-axis-item [categories]="months" [title]="{ text: 'Mois' }">
        </kendo-chart-category-axis-item>
      </kendo-chart-category-axis>

      <!-- Axe des valeurs (€) -->
      <kendo-chart-value-axis>
        <kendo-chart-value-axis-item [title]="{ text: 'Montant (€)' }" [labels]="{ format: '{0:n0} €' }">
        </kendo-chart-value-axis-item>
      </kendo-chart-value-axis>

      <kendo-chart-series>
        <!-- Série CA réalisé -->
        <kendo-chart-series-item
          type="column"
          [data]="revenueData"
          name="CA réalisé"
          color="#3b82f6"
          [gap]="0.3"
          [spacing]="0.1"
        ></kendo-chart-series-item>

        <!-- Série objectif (ligne) -->
        <kendo-chart-series-item
          type="line"
          [data]="targetData"
          name="Objectif"
          color="#ef4444"
          [width]="2"
          [dashType]="'dash'"
          [markers]="{ visible: true, size: 6 }"
        ></kendo-chart-series-item>
      </kendo-chart-series>

      <!-- Tooltip au survol -->
      <kendo-chart-tooltip [format]="'{0:c0}'"></kendo-chart-tooltip>
    </kendo-chart>
  `,
})
export class SalesChartComponent implements OnInit {
  months       = ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun'];
  revenueData  = [42000, 55000, 49000, 63000, 71000, 58000];
  targetData   = [50000, 50000, 52000, 55000, 60000, 65000];

  ngOnInit(): void {
    // Les données peuvent venir d'un service HTTP
  }
}

Donut Chart pour les proportions

// budget-donut.component.ts
import { Component } from '@angular/core';
import { ChartsModule } from '@progress/kendo-angular-charts';

@Component({
  selector: 'app-budget-donut',
  standalone: true,
  imports: [ChartsModule],
  template: `
    <kendo-chart style="height: 350px">
      <kendo-chart-title text="Répartition du budget"></kendo-chart-title>
      <kendo-chart-legend position="right"></kendo-chart-legend>

      <kendo-chart-series>
        <kendo-chart-series-item
          type="donut"
          [data]="budgetData"
          field="value"
          categoryField="category"
          [labels]="{ visible: true, content: labelContent }"
        ></kendo-chart-series-item>
      </kendo-chart-series>

      <kendo-chart-tooltip>
        <ng-template kendoChartSeriesTooltipTemplate let-dataItem="dataItem">
          <strong>{{ dataItem.category }}</strong><br>
          {{ dataItem.value | number:'1.0-0' }} € ({{ dataItem.percentage | percent:'1.1-1' }})
        </ng-template>
      </kendo-chart-tooltip>
    </kendo-chart>
  `,
})
export class BudgetDonutComponent {
  budgetData = [
    { category: 'Développement', value: 45000 },
    { category: 'Marketing',     value: 25000 },
    { category: 'Design',        value: 15000 },
    { category: 'Infrastructure',value: 10000 },
    { category: 'Formation',     value: 5000  },
  ];

  // Affiche le pourcentage dans le label de chaque segment
  labelContent = (e: any) => `${(e.percentage * 100).toFixed(0)}%`;
}

Dialogs et notifications

Kendo UI propose trois composants pour les feedbacks utilisateur : Dialog (modale confirmable), Window (fenêtre draggable/resizable) et Notification (toast messages). Tous sont accessibles et gérés programmatiquement via des services.

Dialog de confirmation

// delete-button.component.ts
import { Component } from '@angular/core';
import { DialogsModule, DialogService, DialogRef } from '@progress/kendo-angular-dialogs';
import { ButtonsModule } from '@progress/kendo-angular-buttons';

@Component({
  selector: 'app-delete-button',
  standalone: true,
  imports: [DialogsModule, ButtonsModule],
  template: `
    <button kendoButton themeColor="error" (click)="confirmDelete()">
      Supprimer l'article
    </button>
  `,
})
export class DeleteButtonComponent {
  constructor(private dialogService: DialogService) {}

  confirmDelete(): void {
    // Ouvre une boîte de dialogue de confirmation
    const dialog: DialogRef = this.dialogService.open({
      title:   'Confirmer la suppression',
      content: 'Êtes-vous sûr de vouloir supprimer cet article ? Cette action est irréversible.',
      actions: [
        { text: 'Annuler' },
        { text: 'Supprimer', themeColor: 'error', primary: true },
      ],
      width:        450,
      minWidth:     250,
      preventAction: (ev) => {
        // Empêche la fermeture sur Echap si l'action primaire est en cours
        return false;
      }
    });

    // Écoute le résultat
    dialog.result.subscribe((result: any) => {
      if (result.text === 'Supprimer') {
        console.log('Suppression confirmée !');
        // Appel au service de suppression
      } else {
        console.log('Suppression annulée.');
      }
    });
  }
}

Notifications (Toast)

// notification-demo.component.ts
import { Component } from '@angular/core';
import { NotificationService } from '@progress/kendo-angular-notification';
import { ButtonsModule } from '@progress/kendo-angular-buttons';

@Component({
  selector: 'app-notification-demo',
  standalone: true,
  imports: [ButtonsModule],
  template: `
    <div class="d-flex flex-wrap gap-2">
      <button kendoButton themeColor="success" (click)="showSuccess()">✓ Succès</button>
      <button kendoButton themeColor="info"    (click)="showInfo()">ℹ Info</button>
      <button kendoButton themeColor="warning" (click)="showWarning()">⚠ Avertissement</button>
      <button kendoButton themeColor="error"   (click)="showError()">✕ Erreur</button>
    </div>
  `,
})
export class NotificationDemoComponent {
  constructor(private notifService: NotificationService) {}

  showSuccess(): void {
    this.notifService.show({
      content:      'Article enregistré avec succès !',
      type:         { style: 'success', icon: true },
      position:     { horizontal: 'right', vertical: 'top' },
      animation:    { type: 'slide', duration: 400 },
      hideAfter:    3000, // Ferme automatiquement après 3s
      closable:     true,
    });
  }

  showInfo(): void {
    this.notifService.show({
      content:  'Mise à jour disponible. Rechargez la page.',
      type:     { style: 'info', icon: true },
      position: { horizontal: 'center', vertical: 'top' },
      hideAfter: 5000,
    });
  }

  showWarning(): void {
    this.notifService.show({
      content:  'Votre session expire dans 5 minutes.',
      type:     { style: 'warning', icon: true },
      position: { horizontal: 'right', vertical: 'bottom' },
    });
  }

  showError(): void {
    this.notifService.show({
      content:  'Erreur lors de la sauvegarde. Réessayez.',
      type:     { style: 'error', icon: true },
      position: { horizontal: 'right', vertical: 'top' },
      closable: true,
    });
  }
}

Thèmes et personnalisation

Kendo UI for Angular propose trois thèmes officiels : Default, Bootstrap et Material. La personnalisation se fait via des variables SCSS ou l'outil en ligne Kendo UI ThemeBuilder.

Personnalisation via SCSS

// src/styles.scss — personnaliser le thème Kendo
// Importer uniquement les sources SCSS (pas le CSS compilé)
@use "@progress/kendo-theme-default/scss/index.scss" with (
  // Couleur primaire de votre marque
  $kendo-color-primary: #2563eb,

  // Couleur de fond des composants
  $kendo-component-bg: #ffffff,

  // Radius des bords (cohérence avec votre design system)
  $kendo-border-radius: 6px,

  // Taille de police de base
  $kendo-font-size: 14px,

  // Couleur du texte principal
  $kendo-body-text: #1e293b,

  // Hauteur des lignes dans le Grid
  $kendo-grid-row-height: 40px,

  // Couleur d'accentuation au survol
  $kendo-selected-bg: #dbeafe,
  $kendo-selected-text: #1d4ed8,

  // Style des boutons
  $kendo-button-border-radius: 4px,
);

Thème Bootstrap — intégration avec Bootstrap 5

// angular.json — utiliser le thème Bootstrap pour une cohérence visuelle
// styles:
// "node_modules/@progress/kendo-theme-bootstrap/dist/all.css"

// Les composants Kendo adoptent automatiquement les couleurs Bootstrap :
// primary, secondary, success, warning, danger, info

// Exemple : bouton Kendo avec la couleur Bootstrap "success"
// <button kendoButton themeColor="success">Valider</button>
// Résultat visuel : identique à <button class="btn btn-success">

Dark mode avec variables CSS

// src/styles.scss — support du dark mode
@media (prefers-color-scheme: dark) {
  // Surcharger les tokens Kendo pour le mode sombre
  .k-grid,
  .k-dialog,
  .k-notification {
    --kendo-component-bg: #1e293b;
    --kendo-component-text: #f1f5f9;
    --kendo-grid-header-bg: #0f172a;
    --kendo-grid-header-text: #e2e8f0;
    --kendo-grid-alt-row-bg: #162032;
  }
}

// Classe manuelle pour toggle dark mode via JavaScript
[data-theme="dark"] {
  .k-grid {
    background-color: #1e293b;
    color: #f1f5f9;
  }
}
Checklist personnalisation Kendo :
  • Utiliser les sources SCSS (pas le CSS compilé) pour surcharger les variables
  • Choisir le thème Bootstrap si votre projet utilise déjà Bootstrap
  • Tester le ThemeBuilder en ligne avant d'écrire du SCSS manuellement
  • Préférer les variables CSS --kendo-* pour les modifications légères sans recompilation SCSS
  • Vérifier le contraste des couleurs personnalisées (WCAG AA minimum)

Utilisation avec Angular Standalone

Depuis Angular 17, les composants standalone sont la norme. Kendo UI for Angular supporte pleinement ce pattern depuis la version 13. Plus besoin d'importer les modules dans un AppModule.

Import direct des composants standalone

// dashboard.component.ts — import Kendo en mode standalone
import { Component, signal, computed } from '@angular/core';

// Imports Kendo UI directs (standalone compatible)
import { GridModule }          from '@progress/kendo-angular-grid';
import { ChartsModule }        from '@progress/kendo-angular-charts';
import { ButtonsModule }       from '@progress/kendo-angular-buttons';
import { DropDownsModule }     from '@progress/kendo-angular-dropdowns';
import { NotificationModule }  from '@progress/kendo-angular-notification';
import { DateInputsModule }    from '@progress/kendo-angular-dateinputs';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  // Importer uniquement les modules nécessaires pour ce composant
  imports: [
    GridModule,
    ChartsModule,
    ButtonsModule,
    DropDownsModule,
    NotificationModule,
    DateInputsModule,
  ],
  template: `
    <div class="container-fluid">
      <div class="row g-4">
        <div class="col-12">
          <h1>Dashboard</h1>
          <!-- Filtre de période -->
          <kendo-daterange class="me-3">
            <kendo-dateinput kendoDateRangeStartInput [(value)]="periodStart" format="dd/MM/yyyy">
            </kendo-dateinput>
            <kendo-dateinput kendoDateRangeEndInput [(value)]="periodEnd" format="dd/MM/yyyy">
            </kendo-dateinput>
            <kendo-daterange-popup></kendo-daterange-popup>
          </kendo-daterange>
          <button kendoButton themeColor="primary" (click)="loadData()">Actualiser</button>
        </div>

        <!-- Graphique des ventes -->
        <div class="col-lg-8">
          <kendo-chart style="height: 300px">
            <kendo-chart-series>
              <kendo-chart-series-item type="line" [data]="salesData()" color="#3b82f6">
              </kendo-chart-series-item>
            </kendo-chart-series>
          </kendo-chart>
        </div>

        <!-- KPI cards -->
        <div class="col-lg-4">
          <div class="card mb-3">
            <div class="card-body">
              <h6 class="text-muted">CA Total</h6>
              <h3 class="text-primary fw-bold">{{ totalRevenue() | number:'1.0-0' }} €</h3>
            </div>
          </div>
        </div>
      </div>
    </div>
  `,
})
export class DashboardComponent {
  periodStart = new Date(new Date().getFullYear(), 0, 1); // 1er janvier
  periodEnd   = new Date();

  salesData  = signal([42000, 55000, 49000, 63000, 71000, 58000]);
  totalRevenue = computed(() => this.salesData().reduce((s, v) => s + v, 0));

  loadData(): void {
    // Recharge les données selon la période sélectionnée
    console.log('Chargement pour', this.periodStart, '→', this.periodEnd);
  }
}

Accessibilité et bonnes pratiques

Kendo UI for Angular est l'une des rares librairies UI à revendiquer et maintenir une conformité WCAG 2.1 AA pour l'ensemble de ses composants. Voici les points clés à connaître pour une intégration accessible.

Navigation clavier dans le Grid

<!-- Navigation clavier activée par défaut dans Kendo Grid -->
<kendo-grid
  [data]="employees"
  [navigatable]="true"
  [selectable]="{ enabled: true, mode: 'multiple', drag: true }"
  (selectionChange)="onSelectionChange($event)"
  aria-label="Liste des employés"
>
  <!-- Chaque cellule est focusable via Tab/flèches directionnelles -->
  <kendo-grid-column field="name"   title="Nom"    [width]="200"></kendo-grid-column>
  <kendo-grid-column field="role"   title="Rôle"   [width]="150"></kendo-grid-column>
  <kendo-grid-column field="email"  title="Email"  [width]="250"></kendo-grid-column>
</kendo-grid>

Labels et descriptions ARIA

<!-- Bonne pratique : toujours associer un label aux composants Kendo -->
<div class="mb-3">
  <!-- kendo-label génère automatiquement l'attribut for/id -->
  <kendo-label text="Date de naissance" [for]="dob"></kendo-label>
  <kendo-datepicker
    #dob
    [(value)]="birthDate"
    format="dd/MM/yyyy"
    [aria-describedby]="'dob-hint'"
  ></kendo-datepicker>
  <!-- Message d'aide lié via aria-describedby -->
  <small id="dob-hint" class="text-muted">Format : JJ/MM/AAAA</small>
</div>

<!-- États d'erreur accessibles -->
<kendo-numerictextbox
  [formControl]="ageControl"
  [aria-label]="'Âge en années'"
  [aria-invalid]="ageControl.invalid && ageControl.touched"
  [aria-errormessage]="'age-error'"
></kendo-numerictextbox>
<span id="age-error" role="alert" *ngIf="ageControl.invalid && ageControl.touched">
  L'âge doit être compris entre 0 et 150 ans.
</span>
Test d'accessibilité : Testez vos composants Kendo avec un lecteur d'écran (NVDA, VoiceOver). Vérifiez que tous les contrôles interactifs sont atteignables au clavier, que les états actifs/désactivés sont annoncés, et que les tableaux Grid disposent de captions appropriées via aria-label.

Comparaison avec PrimeNG et Angular Material

Trois librairies dominent l'écosystème Angular pour les composants UI enterprise. Voici une comparaison objective pour vous aider à choisir.

Critère Kendo UI (Telerik) PrimeNG Angular Material
Licence Commerciale (essai 30j) MIT (open source) MIT (open source)
Nombre de composants 100+ 90+ ~35
Grid / DataTable Excellent (virtualisation, export Excel) Très bon Basique (mat-table)
Charts inclus Oui (20+ types) Oui (via PrimeChart) Non
Scheduler Oui (agenda complet) Oui Non
Accessibilité WCAG 2.1 AA certifié Partielle WCAG 2.1 AA
Support professionnel Inclus dans la licence Payant (PrimePro) Communauté / Google
Angular Signals Support progressif Support progressif Support complet
Idéal pour Applications enterprise, dashboards lourds Projets open source, apps variées Respect strict Material Design

Quand choisir Kendo UI ?

  • Votre application affiche des grilles de données avec 10 000+ lignes
  • Vous avez besoin d'export Excel/PDF natif sans librairie tierce
  • La conformité WCAG 2.1 est une exigence légale ou contractuelle
  • Vous avez un budget pour la licence et valorisez le support dédié
  • Votre équipe a besoin d'un Scheduler/agenda enterprise
  • Vous utilisez déjà d'autres produits Progress/Telerik (Reporting, Testing)

Conclusion

Kendo UI for Angular s'impose comme la référence des librairies UI enterprise pour Angular. Son Grid virtualisé, ses charts intégrés, son Scheduler complet et sa conformité WCAG 2.1 AA en font le choix naturel pour les applications back-office complexes. L'investissement dans la licence est compensé par le gain de temps de développement et la qualité du support.

La transition vers les composants standalone Angular 17+ est fluide, et la compatibilité avec Angular Signals progresse à chaque version. Pour les projets avec des budgets contraints, les éditions open source partielles (Kendo Free Components) offrent un point d'entrée accessible. Pour les projets enterprise exigeants, Kendo UI reste une valeur sûre depuis plus de dix ans dans l'écosystème Angular.

Récapitulatif pour bien démarrer avec Kendo UI :
  • Installer via ng add @progress/kendo-angular-grid pour une configuration automatique
  • Choisir le thème Bootstrap si votre projet utilise déjà Bootstrap 5
  • Importer uniquement les modules nécessaires (tree-shaking optimisé)
  • Activer [navigatable]="true" sur le Grid pour la navigation clavier
  • Toujours associer des kendo-label à vos composants de formulaires
  • Utiliser le ThemeBuilder en ligne pour personnaliser les couleurs sans SCSS complexe
  • Tester avec un lecteur d'écran avant la mise en production

Partager