Angularのホスト要素を動的にスタイリングする方法

に公開

共通UIコンポーネントで頻出するホスト要素のスタイリング方法を、整理した。

ホスト要素の説明はこちら。
https://angular.jp/guide/components/host-elements

前提条件

以下の環境で動作確認済み。

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 20.0.4
Node: 22.14.0
Package Manager: pnpm 10.10.0
OS: darwin arm64

Angular: 20.0.5
... animations, common, compiler, compiler-cli, core, forms
... platform-browser

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.2000.4
@angular-devkit/core         20.0.4
@angular-devkit/schematics   20.0.4
@angular/build               20.0.4
@angular/cdk                 20.0.4
@angular/cli                 20.0.4
@angular/material            20.0.4
@schematics/angular          20.0.4
rxjs                         7.8.2
typescript                   5.8.3
zone.js                      0.15.1

サンプルコードは読みやすさを優先して、import文を省略している。完全なコードはソースコードを確認してほしい。

boolean型のinputでclass名を制御するケース

状態に応じてクラスを付けたいときは、[class.xxx]を使う。

main.ts
<app-text text="てすと" [active]="true" />
text.component.ts
@Component({
  selector: 'app-text',
  template: `{{text()}}`,
  host: {
    '[class.active]': 'active()',
    '[class.disabled]': 'disabled()',
  },
  styleUrl: `text.component.css`,
})
export class TextComponent {
  text = input.required<string>();
  active = input.required<boolean>();
  disabled = input<boolean>(false);
}
text.component.css
:host.active {
  /* active時のスタイル */
}
:host.disabled {
  /* disable時のスタイル */
}

string型のinputでstyleを制御するケース

inputで渡された値をそのまま[style.xxx]にバインドする。

main.ts
<app-text text="てすと" color="blue" size="lg" />
text.component.ts
type Color = 'red' | 'blue';
type Size = 'sm' | 'md' | 'lg';

@Component({
  selector: 'app-text',
  template: `{{text()}}`,
  host: {
    '[style.color]': 'color()',
    '[style.font-size.px]': 'fontSize()',
  },
})
export class TextComponent {
  text = input.required<string>();
  color = input<Color>('red');
  size = input<Size>('md');
  
  fontSize = computed(() => {
    const size = this.size();
    switch (size) {
      case 'sm':
        return 10;
      case 'md':
        return 16;
      case 'lg':
        return 24;
    }
  });
}

string型のinputでclass名を制御するケース

複数のclass名を使いたいときは、joinして[class]に渡す。
[class.color][class.size]のような書き方は使えない。

main.ts
<app-text text="てすと" color="blue" size="lg" />
text.component.ts
type Color = 'red' | 'blue';
type Size = 'sm' | 'md' | 'lg';

@Component({
  selector: 'app-text',
  template: `{{text()}}`,
  host: {
    // NG
    // '[class.color]': 'color()',
    // '[class.size]': 'size()',

    // OK
    '[class]': 'classes()',
  },
  styleUrl: `text.component.css`,
})
export class TextComponent {
  text = input.required<string>();
  color = input<Color>('red');
  size = input<Size>('md');

  classes = computed(() => {
    const color = this.color();
    const size = this.size();
    return [color, size].join(' ');
  });
}
text.component.css
:host.red {
  color: red;
}
:host.blue {
  color: blue;
}
:host.sm {
  font-size: 10px;
}
:host.md {
  font-size: 16px;
}
:host.lg {
  font-size: 24px;
}

ソースコード

Discussion