← Back to scenarios
ScenarioCatalog DB

UI accessibility enhancement

Wrap a UI component with labels, keyboard handling, and hints without changing the base component.

Problem

A UI system must add optional accessibility behavior to individual components while preserving the base UI contract and avoiding modifications to each original component implementation.

Related patterns

Implementations

Decorator

TypeScriptApplication

Decorator in TypeScript

Adds logging and retry behavior to a notification sender by composing wrappers that preserve the same sending interface.

TypeScript
interface NotificationSender {
  send(recipient: string, message: string): Promise<void>;
}

class EmailSender implements NotificationSender {
  async send(recipient: string, message: string) {
    console.log(`Sending email to ${recipient}: ${message}`);
  }
}

abstract class NotificationSenderDecorator
  implements NotificationSender
{
  constructor(
    protected readonly sender: NotificationSender,
  ) {}

  send(recipient: string, message: string) {
    return this.sender.send(recipient, message);
  }
}

class LoggingSender extends NotificationSenderDecorator {
  async send(recipient: string, message: string) {
    console.log(`Starting notification for ${recipient}`);

    await super.send(recipient, message);

    console.log(`Completed notification for ${recipient}`);
  }
}

class RetryingSender extends NotificationSenderDecorator {
  async send(recipient: string, message: string) {
    try {
      await super.send(recipient, message);
    } catch (error) {
      console.warn("First attempt failed; retrying once.");
      await super.send(recipient, message);
    }
  }
}

const sender = new LoggingSender(
  new RetryingSender(new EmailSender()),
);

void sender.send("team@example.com", "Deployment completed.");

Associated technologies