Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles

On day 24, I create an Alert Bar component to show or hide the close button, apply a new style to the alerts, and change their direction.

Create a Close SVG Icon

Vue 3 application

Create an icons/CloseIcon.vue

<template>…


This content originally appeared on DEV Community and was authored by Connie Leung

On day 24, I create an Alert Bar component to show or hide the close button, apply a new style to the alerts, and change their direction.

Create a Close SVG Icon

Vue 3 application

Create an icons/CloseIcon.vue

<template>
    <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M5.29289 5.29289C5.68342 4.90237 6.31658 4.90237 6.70711 5.29289L12 10.5858L17.2929 5.29289C17.6834 4.90237 18.3166 4.90237 18.7071 5.29289C19.0976 5.68342 19.0976 6.31658 18.7071 6.70711L13.4142 12L18.7071 17.2929C19.0976 17.6834 19.0976 18.3166 18.7071 18.7071C18.3166 19.0976 17.6834 19.0976 17.2929 18.7071L12 13.4142L6.70711 18.7071C6.31658 19.0976 5.68342 19.0976 5.29289 18.7071C4.90237 18.3166 4.90237 17.6834 5.29289 17.2929L10.5858 12L5.29289 6.70711C4.90237 6.31658 4.90237 5.68342 5.29289 5.29289Z" fill="#0F1729"></path>
    </svg>
</template>

Display the close icon in the alert component

<script setup lang="ts">
import CloseIcon from '@/icons/CloseIcon.vue'
</script>
<template>
... omitted to save space ...
<div>
    <button class="btn btn-sm btn-primary" title="Close button" @click="closeAlert">
        <CloseIcon />
    </button>
</div>
</template>

Import the CloseIcon and add the <CloseIcon> within the <template> tags to render the close icon on the button.

SvelteKit application

Create a lib/icons/close-icon.svelte

<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24">
    <path fill-rule="evenodd" clip-rule="evenodd" d="M5.29289 5.29289C5.68342 4.90237 6.31658 4.90237 6.70711 5.29289L12 10.5858L17.2929 5.29289C17.6834 4.90237 18.3166 4.90237 18.7071 5.29289C19.0976 5.68342 19.0976 6.31658 18.7071 6.70711L13.4142 12L18.7071 17.2929C19.0976 17.6834 19.0976 18.3166 18.7071 18.7071C18.3166 19.0976 17.6834 19.0976 17.2929 18.7071L12 13.4142L6.70711 18.7071C6.31658 19.0976 5.68342 19.0976 5.29289 18.7071C4.90237 18.3166 4.90237 17.6834 5.29289 17.2929L10.5858 12L5.29289 6.70711C4.90237 6.31658 4.90237 5.68342 5.29289 5.29289Z" fill="#0F1729"></path>
</svg>

Display the close icon in the alert component

<script lang="ts">
    import CloseIcon from '$lib/icons/close-icon.svelte'
</script>
... omitted to save space ... 
<div>
    <button class="btn btn-sm btn-primary" title="Close button" onclick={closeAlert}>
        <CloseIcon />
    </button>
</div>

Import the CloseIcon and add the <CloseIcon /> in the HTML template to render the close icon on the button.

Angular 20 application

Create a CloseIconComponent

@Component({
  selector: 'app-close-icon',
  template: `
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24">
  <path fill-rule="evenodd" clip-rule="evenodd" d="M5.29289 5.29289C5.68342 4.90237 6.31658 4.90237 6.70711 5.29289L12 10.5858L17.2929 5.29289C17.6834 4.90237 18.3166 4.90237 18.7071 5.29289C19.0976 5.68342 19.0976 6.31658 18.7071 6.70711L13.4142 12L18.7071 17.2929C19.0976 17.6834 19.0976 18.3166 18.7071 18.7071C18.3166 19.0976 17.6834 19.0976 17.2929 18.7071L12 13.4142L6.70711 18.7071C6.31658 19.0976 5.68342 19.0976 5.29289 18.7071C4.90237 18.3166 4.90237 17.6834 5.29289 17.2929L10.5858 12L5.29289 6.70711C4.90237 6.31658 4.90237 5.68342 5.29289 5.29289Z" fill="#0F1729"></path>
</svg>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CloseIconComponent {}

Display the close icon in the alert component

import { NgComponentOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component, computed, input, output, signal } from '@angular/core';
import { AlertType } from '../alert.type';
import { CloseIconComponent, ErrorIconComponent, InfoIconComponent, SuccessIconComponent, WarningIconComponent } from '../icons/icon.component';

@Component({
  selector: 'app-alert',
  imports: [NgComponentOutlet, CloseIconComponent],
  template: `
     ... omitted to save space ...
    <div>
      <button class="btn btn-sm btn-primary" title="Close button" (click)="closeAlert()">
        <app-close-icon />
      </button>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertComponent {}

Import the CloseIconComponent and register it to the imports array of the @Component decorator.

In the inline template, use the app-close-icon selector to render the close icon on the button.

Add Show/Hide checkbox to the AlertBar Component

Vue 3 application

Since Vue 3.4, the recommended approach of two-way data binding is using the defineModel macro.

<script setup lang="ts">
const hasCloseButton = defineModel<boolean>('hasCloseButton', { default: true })
</script>

Declare a defineModel<boolean> and assign the value to the hasCloseButton ref. { default: true } means the default value of the ref is true The checkbox is checked and the alert component should show a close button.

<template>
  <div>
    <p class="mb-[0.75rem]">
      <span>Has close button? </span>
      <input type="checkbox" class="mr-[0.5rem]" v-model="hasCloseButton" />
    </p>
  </div>
</template>

In the template, the v-model directive is added to the checkbox input and binded to hasCloseButton. The hasCloseButton enables 2-way data binding and passes the value up to the parent component, which is the AlertList component.

SvelteKit application

In Svelte 5, two-way binding is done with the $bindable function. Moreover, $bindable must be used with $props together. We will update the Prop type to add hasCloseButton and destructure the property from the $prop() call.


 type Props = {
    hasCloseButton: boolean;
}

let { 
    hasCloseButton = $bindable(), 
}: Props = $props();
<div>
    <p class="mb-[0.75rem]">
        <span>Has close button?</span>
        <input type="checkbox" class="mr-[0.5rem]" bind:checked={hasCloseButton} />
    </p>
</div>

In the template, the bind:checked attribute of the checkbox is binded to hasCloseButton. The hasCloseButton enables 2-way data binding and passes the value up to the parent component, which is the AlertList component.

Angular 20 application

In Angular, two-way binding is achieved by the the model Writable signal.

import { ChangeDetectionStrategy, Component, input, model } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-alert-bar',
  imports: [],
  template: `
  <div>
    <p class="mb-[0.75rem]">
      <span>Has close button? </span>
      <input type="checkbox" class="mr-[0.5rem]" [(ngModel)]="hasCloseButton" />
      </select>
    </p>
  </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertBarComponent {
  hasCloseButton = model<boolean>(true);
}

Declare a model<boolean>(true) and assign the value to the hasCloseButton signal. The default value of model is true, so the checkbox is checked and the alert component should show a close button.

Pass hasCloseButton up to the AlertList Component

Vue 3 application

<script setup lang="ts">
import { computed, ref } from 'vue';

const hasCloseButton = ref(true)
</script>

Declare a hasCloseButton ref in the AlertList component to receive the value from the child.

<template>
  <h2>Alert Components (Vue ver.)</h2>

  <AlertBar
    v-model:hasCloseButton="hasCloseButton"
  />
</template>

A Vue component allows multiple v-model bindings.

v-model:hasCloseButton="hasCloseButton" binds the child's hasCloseButton to the hasCloseButton ref.

SvelteKit application

<script lang="ts">
    import AlertBar from './alert-bar.svelte';

    let hasCloseButton = $state(true);
</script>

Declare a hasCloseButton rune in the AlertList component to receive the value from the child.

<AlertBar {configs} 
    bind:hasCloseButton={hasCloseButton} 
/>

bind:hasCloseButton={hasCloseButton} means the AlertList component listens to what the hasCloseButton prop of the AlerBarcomponent has to say.

Angular 20 application

import { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';
import { AlertBarComponent } from '../alert-bar/alert-bar.component';

@Component({
  selector: 'app-alert-list',
  imports: [AlertBarComponent],
  template: `
    <app-alert-bar 
      [(hasCloseButton)]="hasCloseButton" 
    />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertListComponent {
  hasCloseButton = signal<boolean>(true);
}

Declare a hasCloseButton signal in the AlertList component to receive the value from the child.

Use banana-in-the-box syntax, [(expression)], to perform two-way binding for the AlertList and AlertBar components.

Show/Hide Close Button in the Alert Component

Vue 3 application

const hasCloseButton = ref(true)

const alertConfig = computed(() => ({
  hasCloseButton: hasCloseButton.value,
}))

Define a alertConfig computed ref to create an object to store the value of hasCloseButton.value.

<template>
    <Alert v-for="{ type, message } in alerts"
        class="mb-[0.75rem]"
        :key="type"
        :type="type"
        :alertConfig="alertConfig">
        {{  message }}
    </Alert>
</template>

Pass the alertConfig to the alertConfig prop of the Alert component.

<script setup lang="ts">
    import { computed, ref } from 'vue'
    import CloseIcon from '@/icons/CloseIcon.vue'

    type Props = {
        alertConfig: {
            hasCloseButton: boolean
        },
        type: string
    }

    const { type, alertConfig } = defineProps<Props>()

    ... omit the template codes ...
</script>

In the Alert component, add the new alertConfig property to the Prop type. Destructure the alertConfig from the defineProps macro.

<template>
  <div role="alert" :class="alertClasses" v-if="!closed">
    <component :is="icon" />
    <span><slot></slot></span>
    <div v-if="alertConfig.hasCloseButton">
        <button class="btn btn-sm btn-primary" alt="Close button" @click="closeAlert">
            <CloseIcon />
        </button>
    </div>
  </div>
</template>

If alertConfig.hasCloseButton is true, the close button will be shown. Otherwise, it is hidden.

SvelteKit application

<script lang="ts">
    import AlertBar from './alert-bar.svelte';
    import Alert from './alert.svelte';
    import type { AlertMessage } from './alert.type';

    let hasCloseButton = $state(true);
</script>

Declare a hasCloseButton rune in the AlertList component to receive the value from the child.

{#each alerts as alert (alert.type) } 
    <Alert {alert} {hasCloseButton} />
{/each}

Pass the hasCloseButton rune to the hasCloseButton prop of the Alert component.

<AlertBar {configs} 
    bind:hasCloseButton={hasCloseButton} 
/>

bind:hasCloseButton={hasCloseButton} means the AlertList component listens to what the hasCloseButton prop of the AlertBarcomponent has to say.

<script lang="ts">
    type Props = {
        ... other properties ...
        hasCloseButton: boolean;
    }

    const { 
        hasCloseButton, 
    }: Props = $props();
</script>

In the Alert component, add a hasCloseButton property to the Prop type and destructure the property from the object.

{#if !closed}
    <div role="alert" class={alertClasses}>
        ... omit the template code...
        {#if hasCloseButton} 
            <div>
                <button class="btn btn-sm btn-primary" title="Close button" onclick={closeAlert}>
                    <CloseIcon />
                </button>
            </div>
        {/if}
    </div>
{/if}

If hasCloseButton is true, the button is rendered. Otherwise, the button is hidden.

Angular 20 application

import { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';
import { AlertBarComponent } from '../alert-bar/alert-bar.component';

@Component({
  selector: 'app-alert-list',
  imports: [AlertBarComponent],
  template: `
    <app-alert-bar 
      [(hasCloseButton)]="hasCloseButton" 
    />

    @for (alert of alerts(); track alert.type) {
      <app-alert [type]="alert.type" 
        [alertConfig]="alertConfig()"
      >
        {{ alert.message }}
      </app-alert>
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertListComponent {
  hasCloseButton = signal<boolean>(true);

  alertConfig = computed(() => ({
    hasCloseButton: this.hasCloseButton(),
  }));
}

Declare a hasCloseButton signal in the AlertList component to receive the value from the child.

Use banana-in-the-box syntax, [(expression)], to perform two-way binding for the AlertList and AlertBar components.

Define a alertConfig computed signal to create an object to store the value of the hasCloseButton signal.

Assign the value of the alertConfig computed signal to the input signal of AlertComponent.

import { NgComponentOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component, computed, input, output, signal } from '@angular/core';
import { AlertType } from '../alert.type';
import { CloseIconComponent, ErrorIconComponent, InfoIconComponent, SuccessIconComponent, WarningIconComponent } from '../icons/icon.component';

@Component({
  selector: 'app-alert',
  imports: [NgComponentOutlet, CloseIconComponent],
  template: `
    @if (!closed()) {
        ... omit the template codes ...
        @if (alertConfig().hasCloseButton) {
        <div>
          <button class="btn btn-sm btn-primary" title="Close button" (click)="closeAlert()">
            <app-close-icon />
          </button>
        </div>
        }
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertComponent {
  type = input.required<AlertType>();

  alertConfig = input.required<{
    hasCloseButton: boolean
  }>();
}

In the AlertComponent, declare an alertConfig required input signal.

If alertConfig().hasCloseButton is true, the button is rendered. Otherwise, the button is hidden.

Next, we will repeat the same procedure to add style and direction dropdown lists to change the styling of the alert component.

Add Alert Style and Direction dropdown lists

Vue 3 application

<script setup lang="ts">
    type Props = {
        config: { 
          styleLabel: string
          styles: { text: string, value: string }[]
          directionLabel: string
          directions: { text: string, value: string }[]
        },
    }

    const props = defineProps<Props>()
    const { config } = props
</script>

Declare a Prop in the AlertBar component to accept the style label, style dropdown list, direction label, and direction dropdown list.

const style = defineModel<string>('style', { default: 'color' })
const direction = defineModel<string>('direction', { default: 'horizontal' })

Declare style and direction ref for two-way data binding. The default value of style is 'color' and the default value of direction is 'horizontal'.

<template>
  <div>
    <p class="mb-[0.75rem]">
      <span>{{ config.styleLabel }}&nbsp;&nbsp;</span>
      <select class="select select-info mr-[0.5rem]" v-model="style">
        <option v-for="{value, text} in config.styles" :key="value" :value="value">
          {{ text }}
        </option>
      </select>
      <span>{{ config.directionLabel }}&nbsp;&nbsp;</span>
      <select class="select select-info mr-[0.5rem]" v-model="direction">
        <option v-for="{ value, text } in config.directions" :key="value" :value="value">
          {{ text }}
        </option>
      </select>
    </p>
  </div>
</template>

Use v-for to iterate config.styles and config.directions to populate the option items of the select dropdown.

SvelteKit application

<script lang="ts">
    import { capitalize } from './capitalize';
    import OpenIcon from './icons/open-icon.svelte';

    type Props = {
        configs: { 
            styleLabel: string
            styles: { text: string, value: string }[]
            directionLabel: string
            directions: { text: string, value: string }[]
        };
        hasCloseButton: string;
        style: string;
        direction: string;
    }

    let { 
        hasCloseButton = $bindable(), 
        style = $bindable(), 
        direction = $bindable(), 
        closedNotifications = $bindable(),
        configs 
    }: Props = $props();
</script>

Add configs, style and direction to the Props type.
Destructure style and direction from $props() and bind them to the AlertList component using $bindable.

 <p class="mb-[0.75rem]">
    <span>{ configs.styleLabel }&nbsp;&nbsp;</span> { style }
    <select class="select select-info mr-[0.5rem]" bind:value={style}>
        {#each configs.styles as s (s.value) }
            <option value={s.value}>
                { s.text }
            </option>
        {/each}
    </select>
    <span>{ configs.directionLabel }&nbsp;&nbsp;</span>
    <select class="select select-info mr-[0.5rem]" bind:value={direction}> 
        {#each configs.directions as d (d.value)}
            <option value={d.value}>
                { d.text }
            </option>
        {/each}
    </select>
</p>

bind:value={style} binds style rune to the style dropdown. bind:value={direction} bind the direction rune to the direction dropdown.

Use #each to iterate the styles and directions lists to populate the dropdown lists.

Angula 20 application

@Component({
  selector: 'app-alert-bar',
  imports: [FormsModule],
  template: `... inline template explained below ...`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertBarComponent {
  config = input.required<{ 
    styleLabel: string
    styles: { text: string, value: string }[]
    directionLabel: string
    directions: { text: string, value: string }[]
  }>();

  hasCloseButton = model<boolean>(true);
  style = model<string>('color');
  direction = model<string>('horizontal');
}

The AlertBarComponent declares a required input signal for the labels and dropdown lists.

Similarly, style and direction are declared model signals for two-way binding.

The component also imports FormsModule to bind the model to the [(ngModel)] in the inline template.

  <div>
    @let c = config();
    <p class="mb-[0.75rem]">
      <span>{{ c.styleLabel }}&nbsp;&nbsp;</span>
      <select class="select select-info mr-[0.5rem]" [(ngModel)]="style">
        @for (style of c.styles; track style.value) {
          <option [ngValue]="style.value">
            {{ style.text }}
          </option>
        }
      </select>
      <span>{{ c.directionLabel }}&nbsp;&nbsp;</span>
      <select class="select select-info mr-[0.5rem]" [(ngModel)]="direction">
        @for (direction of c.directions; track direction.value) {
          <option [ngValue]="direction.value">
            {{ direction.text }}
          </option>
        }
      </select>
    </p>
  </div>

[(ngModel)]="style" binds style to the style dropdown. Similarly, [(ngModel)]="direction" binds direction to the direction dropdown.

The @for loop iterates the styles and directions lists to display the value/text items.

Perform two-way binding

Vue 3 Application

The config ref defines the labels and items of the style and direction.

<script setup lang="ts">
import type { AlertType } from '@/types/alert-type';
import { computed, ref } from 'vue';
import Alert from './Alert.vue';
import AlertBar from './AlertBar.vue';

const hasCloseButton = ref(true)
const style = ref('color');
const direction = ref('horizontal')

const alertConfig = computed(() => ({
  style: style.value,
  direction: direction.value,
  hasCloseButton: hasCloseButton.value,
}))

const config = ref({
  styleLabel: "Alert styles:",
  styles: [
    { text: 'Default', value: 'color' },
    { text: 'Soft', value: 'soft' },
    { text: 'Outline', value: 'outline' },
    { text: 'Dash', value: 'dash' }
  ],
  directionLabel: "Alert direction:",
  directions: [
    { text: 'Horizontal', value: 'horizontal' },
    { text: 'Vertical', value: 'vertical' },
  ]
})
</script>

Similar to hasCloseButton, style and direction pass the values from the AlertBar component to the AlertList component. Then, the alertConfig computed ref returns the value of style and direction. The alertConfig passes the new values to style the Alert component.

<AlertBar
    :config="config"
    v-model:hasCloseButton="hasCloseButton"
    v-model:style="style"
    v-model:direction="direction"
 />

The AlertBar component receives the config prop. The v-model:style="style" binds the style ref of the AlertBar component to style ref of the AlertList component. Similarly, v-model:direction="direction" binds the direction ref of the AlertBar component to the direction ref of the AlertList component.

SvelteKit Application

The labels and items of style and direction are defined in the config rune.

<script lang="ts">
    import AlertBar from './alert-bar.svelte';
    import Alert from './alert.svelte';

    const configs = $state(... same object...);

    let hasCloseButton = $state(true);
    let style = $state('color');
    let direction = $state('horizontal');
</script>

Similar to hasCloseButton, add style and direction runes to the AlertList component.

<AlertBar {configs} 
    bind:hasCloseButton={hasCloseButton} 
    bind:style={style}
    bind:direction={direction}
/>

The AlertBar component receives the config prop to populate the dropdown. The AlertBar uses the bind syntax to pass the style and direction to the AlertList component.

{#each filteredNotification as alert (alert.type) } 
    <Alert {alert} {alertMessage} {notifyClosed} {hasCloseButton} {style} {direction} />
{/each}

Pass the new prop values, style and direction, to the Alert component.

Angular 20 Application

The labels and items of style and direction are defined in the config signal.

import { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';
import { AlertComponent } from '../alert/alert.component';
import { AlertBarComponent } from '../alert-bar/alert-bar.component';

@Component({
  selector: 'app-alert-list',
  imports: [AlertComponent, AlertBarComponent],
  template: `...inline template shown below ...`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertListComponent {
  style = signal<string>('color');
  direction = signal<string>('horizontal');
  hasCloseButton = signal<boolean>(true);

  config = signal({... same object ... });

  alertConfig = computed(() => ({
    hasCloseButton: this.hasCloseButton(),
    style: this.style(),
    direction: this.direction()
  }));
}

Similar to hasCloseButton, add style and direction signal to the AlertList component. The alertConfig computed signal returns the value of the style and direction signals.

 <app-alert-bar 
      [config]="config()" 
      [(style)]="style" 
      [(direction)]="direction"
      [(hasCloseButton)]="hasCloseButton"
/>

The AlertBar component receives the config input to populate the dropdown. The AlertBar uses the banana-in-the-box syntax [(expression)] to bind the style and direction models of the AlertBar component to the style and direction signals of the AlertList component.

[(style)]="style" - The first style is the style model of the AlertBarComponent and the second style is the style signal of the AlertListComponent.

[(direction)]="direction" - The first direction is the direction model of the AlertBarComponent and the second direction is the direction signal of the AlertListComponent.

Apply Style and Direction to Alert Component

Vue 3 Application

 type Props = {
    alertConfig: {
        hasCloseButton: boolean
        style: string
        direction: string
    },
    type: string
}

const { type, alertConfig } = defineProps<Props>()

In the Props type of the Alert component, add style and direction to the alertConfig property.

const alertColor = computed(() => ({
    info: 'alert-info',
    warning: 'alert-warning',
    error: 'alert-error',
    success: 'alert-success'
}[type]))

 const alertStyle = computed(() => ({
    color: '',
    dash: 'alert-dash',
    soft: 'alert-soft',
    outline: 'alert-outline'
}[alertConfig.style]))

const alertDirection = computed(() => ({
    horizontal: 'alert-horizontal',
    vertical: 'alert-vertical',
}[alertConfig.direction]))

const alertClasses = computed(() => `alert ${alertColor.value} ${alertStyle.value} ${alertDirection.value}`)

Create the alertStyle computed ref to derive the style class. Create the alertDirection computed ref to derive the direction class.

The alertClasses computed ref concatenates the style classes of the alert component.

 <template>
  <div role="alert" :class="alertClasses" v-if="!closed">
    <!-- HTML button -->
  </div>
</template>

The alertClasses binds the new styles to the class attribute to change the direction, border style and color.

SvelteKit Application

type Props = {
    hasCloseButton: boolean;
    style: string;
    direction: string;
}

const { 
    hasCloseButton, 
    direction, 
    style 
}: Props = $props();

In the Props type of the Alert component, add style and direction properties.

const alertColor = $derived.by(() => ({
    info: 'alert-info',
    success: 'alert-success',
    warning: 'alert-warning',
    error: 'alert-error',
}[alert.type]));

const alertDirection = $derived.by(() => ({
    horizontal: 'alert-horizontal',
    vertical: 'alert-vertical',
}[direction]));

const alertStyle = $derived.by(() => ({
    color: '',
    soft: 'alert-soft',
    outline: 'alert-outline',
    dash: 'alert-dash',
}[style]));

const alertClasses = $derived(`alert ${alertColor} ${alertDirection} ${alertStyle} mb-[0.75rem]`);

Create the alertStyle derived rune to derive the style class. Create the alertDirection derived rune to derive the direction class.

The alertClasses derived rune concatenates the style classes of the alert component.

{#if !closed}
    <div role="alert" class={alertClasses}>
       <!-- HTML button -->
    </div>
{/if}

The alertClasses binds the new styles to the class attribute to change the direction, border style and color.

Angular 20 Application

@Component({
  selector: 'app-alert',
  imports: [NgComponentOutlet, CloseIconComponent],
  template: `... inline template ...`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertComponent {
  type = input.required<AlertType>();

  alertConfig = input.required<{
    hasCloseButton: boolean
    style: string
    direction: string
  }>();

  alertColor = computed(() => {
    return {
        info: 'alert-info',
        warning: 'alert-warning',
        error: 'alert-error',
        success: 'alert-success'
    }[this.type()]
  });

  alertStyle = computed(() => {
    return {
        color: '',
        dash: 'alert-dash',
        soft: 'alert-soft',
        outline: 'alert-outline'
    }[this.alertConfig().style]
  });

  alertDirection = computed(() => {
    return {
        horizontal: 'alert-horizontal',
        vertical: 'alert-vertical',
    }[this.alertConfig().direction]
  });

  alertClasses = computed(() => `alert ${this.alertColor()} ${this.alertStyle()} ${this.alertDirection()}`);
}

Add style and direction to the alertConfig required input signal.

Create the alertStyle computed signal to derive the style class. Create the alertDirection computed signal to derive the direction class.

The alertClasses computed signal concatenates the style classes of the alert component.

@if (!closed()) {
<div role="alert" class="mb-[0.75rem]" [class]="alertClasses()">
       <!-- HTML button -->
</div>
}

The alertClasses binds the new styles to the class attribute to change the direction, border style and color.

Now, users can select values in the AlertBar component to show/hide the close button, change the border style, direction, and color of the alerts.

Github Repositories

Github Pages

Resources

Resources


This content originally appeared on DEV Community and was authored by Connie Leung


Print Share Comment Cite Upload Translate Updates
APA

Connie Leung | Sciencx (2025-09-27T08:27:12+00:00) Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles. Retrieved from https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/

MLA
" » Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles." Connie Leung | Sciencx - Saturday September 27, 2025, https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/
HARVARD
Connie Leung | Sciencx Saturday September 27, 2025 » Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles., viewed ,<https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/>
VANCOUVER
Connie Leung | Sciencx - » Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/
CHICAGO
" » Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles." Connie Leung | Sciencx - Accessed . https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/
IEEE
" » Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles." Connie Leung | Sciencx [Online]. Available: https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/. [Accessed: ]
rf:citation
» Day 24 – Alert Component Part 3 – Add an Alert Bar to change styles | Connie Leung | Sciencx | https://www.scien.cx/2025/09/27/day-24-alert-component-part-3-add-an-alert-bar-to-change-styles/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.