DEV Community

Cover image for Angular Fullscreen
Milan Barać
Milan Barać

Posted on

Angular Fullscreen

In modern day web applications, the requirement to view certain contents in fullscreen mode is becoming pretty common. Sometimes, this need arises in contexts like image galleries, content editors, or other scenarios.

If you ever need to implement such a feature in Angular application, the easiest way to do this is by creating a directive to support fullscreen mode.

Let’s craft a versatile directive that can seamlessly attach to any HTML element, including the main HTML document. With its adaptability, this directive ensures compatibility with most modern-day browsers’ https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API.

Fullscreen directive

import { DOCUMENT } from '@angular/common';
import {
  Directive,
  ElementRef,
  EventEmitter,
  HostBinding,
  HostListener,
  Inject,
  Input,
  Output,
} from '@angular/core';

export interface FullscreenTransition {
  isFullscreen: boolean;
  element: Element | null;
}

@Directive({
  selector: '[fullscreen]',
  exportAs: 'fullscreen',
})
export class FullscreenDirective {
  private element!: HTMLElement;

  @Input()
  set fullscreen(element: HTMLElement | string) {
    if (element instanceof ElementRef) {
      this.element = element.nativeElement;
    } else if (element instanceof HTMLElement) {
      this.element = element;
    } else if (element === '') {
      this.element = this.doc.documentElement;
    } else {
      throw new Error(
        `Only type HTMLElement or string allowed, got "${typeof element}".`
      );
    }
  }

  get fullscreen(): HTMLElement {
    return this.element;
  }

  @HostBinding('class.fullscreen')
  get isFullscreen(): boolean {
    return this.isFullscreenEnabled();
  }

  @HostListener('document:fullscreenchange')
  private onTransition() {
    const isFullscreen = this.isFullscreen;
    const element = this.element;
    this.change.emit({ isFullscreen, element });
  }

  @Output()
  change = new EventEmitter<FullscreenTransition>();

  constructor(@Inject(DOCUMENT) private doc: Document) {}

  async enter() {
    if (this.fullscreen) {
      await this.enterElementFullscreen(this.fullscreen);
    } else {
      await this.enterDocumentFullscreen();
    }
  }

  async exit() {
    if (this.isFullscreen) {
      await this.exitFullscreen();
    }
  }

  toggle() {
    if (this.isFullscreen) {
      this.exit();
    } else {
      this.enter();
    }
  }

  private async enterDocumentFullscreen() {
    const elem = this.doc.documentElement;
    await this.enterFullscreen(elem);
  }

  private async exitDocumentFullscreen() {
    await this.exitFullscreen();
  }

  private async enterElementFullscreen(elem: HTMLElement) {
    await this.enterFullscreen(elem);
  }

  private async exitElementFullscreen() {
    await this.exitFullscreen();
  }

  private async enterFullscreen(elem: HTMLElement) {
    await ((elem as any).requestFullscreen?.() ||
      (elem as any).webkitRequestFullscreen?.() ||
      (elem as any).mozRequestFullScreen?.() ||
      (elem as any).msRequestFullscreen?.());
  }

  private async exitFullscreen() {
    await ((this.doc as any).exitFullscreen?.() ||
      (this.doc as any).webkitExitFullscreen?.() ||
      (this.doc as any).mozCancelFullScreen?.() ||
      (this.doc as any).msExitFullscreen?.());
  }

  private isFullscreenEnabled(): boolean {
    return !!(
      (this.doc as any).fullscreenElement ||
      (this.doc as any).webkitFullscreenElement ||
      (this.doc as any).mozFullScreenElement ||
      (this.doc as any).msFullscreenElement
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Implementation of this directive is pretty straightforward.

Triggering the specific HTML element in fullscreen mode:

<div
  #fullscreen
  [fullscreen]="fullscreen"
  (change)="onFullscreenChange($event)"
>
</div>
Enter fullscreen mode Exit fullscreen mode

Triggering the entire HTML document in fullscreen mode:

<div
  #fullscreen
  fullscreen
  (change)="onFullscreenChange($event)"
>
</div>
Enter fullscreen mode Exit fullscreen mode

The HTML element bound to directive is getting a fullscreenCSS class, to allow further styling of the element, if needed:

@HostBinding('class.fullscreen')
get isFullscreen(): boolean {
  return this.isFullscreenEnabled();
}
Enter fullscreen mode Exit fullscreen mode

Event changeemitter can be used to track fullscreen transition:

@HostListener('document:fullscreenchange')
private onTransition() {
  const isFullscreen = this.isFullscreen;
  const element = this.element;
  this.change.emit({ isFullscreen, element });
}

@Output()
change = new EventEmitter<FullscreenTransition>();
Enter fullscreen mode Exit fullscreen mode
export interface FullscreenTransition {
  isFullscreen: boolean;
  element: Element | null;
}
Enter fullscreen mode Exit fullscreen mode
onFullscreenChange(event: FullscreenTransition) {
  this.isFullscreen = event.isFullscreen;
}
Enter fullscreen mode Exit fullscreen mode

Incorporating fullscreen functionality into Angular applications using a custom directive offers users a seamless and immersive experience. By leveraging the flexibility and compatibility of modern browsers, developers can enhance the usability of their web applications. With the provided directive and accompanying demo, implementing fullscreen mode becomes easy, empowering developers to create dynamic and engaging user interfaces.

This is the final result of the demo application:

demo application

Github project · Stackblitz example

Top comments (0)