Fullscreen
The Fullscreen component provides an interface to the Fullscreen API, enabling your Progressive Web App to display content in fullscreen mode. This creates an immersive experience by removing browser chrome and utilizing the entire screen space.
This component is particularly useful for:
Media players and video streaming applications
Photo galleries and image viewers
Presentation and slideshow applications
Gaming applications
Data visualization and dashboard applications
Reading apps and e-books
Browser Support
The Fullscreen API is widely supported in modern browsers. However, browser vendors may have different implementations and require user interaction to activate fullscreen mode.
Usage
Fullscreen for Entire Page
<section {{ stimulus_controller('@pwa/fullscreen') }}>
<h1>My Presentation</h1>
<div class="content">
<!-- Your content here -->
</div>
<button {{ stimulus_action('@pwa/fullscreen', 'request', 'click') }}>
Enter Fullscreen
</button>
<button {{ stimulus_action('@pwa/fullscreen', 'exit', 'click') }}>
Exit Fullscreen
</button>
</section>
<script>
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen, element } = event.detail;
console.log('Fullscreen:', fullscreen ? 'active' : 'inactive');
});
</script>Fullscreen for Specific Element
<section {{ stimulus_controller('@pwa/fullscreen') }}>
<img
id="gallery-image"
src="https://picsum.photos/800/600"
alt="Sample Image"
class="max-w-full"
>
<div class="controls">
<button {{ stimulus_action('@pwa/fullscreen', 'request', 'click', {target: '#gallery-image'}) }}>
View Image Fullscreen
</button>
<button {{ stimulus_action('@pwa/fullscreen', 'exit', 'click') }}>
Exit Fullscreen
</button>
</div>
</section>Video Player with Fullscreen
<div {{ stimulus_controller('@pwa/fullscreen') }}>
<div id="video-container" class="video-wrapper">
<video id="main-video" controls>
<source src="/videos/sample.mp4" type="video/mp4">
</video>
<div class="video-controls">
<button {{ stimulus_action('@pwa/fullscreen', 'request', 'click', {target: '#video-container'}) }}>
⛶ Fullscreen
</button>
</div>
</div>
</div>
<script>
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen } = event.detail;
const video = document.getElementById('main-video');
if (fullscreen) {
// Auto-play when entering fullscreen
video.play();
}
});
document.addEventListener('pwa--fullscreen:error', (event) => {
console.error('Fullscreen error:', event.detail);
alert('Unable to enter fullscreen mode');
});
</script>Image Gallery with Fullscreen
<div {{ stimulus_controller('@pwa/fullscreen') }}>
<div class="gallery">
<div class="image-grid">
<img id="img-1" src="https://picsum.photos/400/300?random=1" alt="Photo 1" class="gallery-item">
<img id="img-2" src="https://picsum.photos/400/300?random=2" alt="Photo 2" class="gallery-item">
<img id="img-3" src="https://picsum.photos/400/300?random=3" alt="Photo 3" class="gallery-item">
</div>
</div>
</div>
<script>
document.querySelectorAll('.gallery-item').forEach(img => {
img.addEventListener('click', function() {
const controller = document.querySelector('[data-controller="@pwa/fullscreen"]');
controller.dispatchEvent(new CustomEvent('request', {
detail: {
params: {
target: `#${this.id}`
}
}
}));
});
});
// Exit fullscreen on Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
const controller = document.querySelector('[data-controller="@pwa/fullscreen"]');
controller.dispatchEvent(new CustomEvent('exit'));
}
});
</script>Presentation Mode with Navigation
<div {{ stimulus_controller('@pwa/fullscreen') }}>
<div id="presentation" class="slides-container">
<div class="slide active">
<h2>Slide 1</h2>
<p>Introduction</p>
</div>
<div class="slide">
<h2>Slide 2</h2>
<p>Main Content</p>
</div>
<div class="slide">
<h2>Slide 3</h2>
<p>Conclusion</p>
</div>
</div>
<div class="presentation-controls">
<button {{ stimulus_action('@pwa/fullscreen', 'request', 'click', {target: '#presentation'}) }}>
Start Presentation
</button>
</div>
</div>
<script>
let currentSlide = 0;
const slides = document.querySelectorAll('.slide');
function showSlide(index) {
slides.forEach(slide => slide.classList.remove('active'));
slides[index].classList.add('active');
}
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen } = event.detail;
if (fullscreen) {
// Enable keyboard navigation in fullscreen
document.addEventListener('keydown', navigateSlides);
} else {
// Disable keyboard navigation when exiting
document.removeEventListener('keydown', navigateSlides);
}
});
function navigateSlides(e) {
if (e.key === 'ArrowRight' && currentSlide < slides.length - 1) {
currentSlide++;
showSlide(currentSlide);
} else if (e.key === 'ArrowLeft' && currentSlide > 0) {
currentSlide--;
showSlide(currentSlide);
}
}
</script>
<style>
.slide {
display: none;
padding: 2rem;
height: 100vh;
align-items: center;
justify-content: center;
}
.slide.active {
display: flex;
flex-direction: column;
}
.presentation-controls {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
</style>Parameters
None
Actions
request
requestTriggers fullscreen mode for the entire document or a specific element.
Parameters:
target(string, optional): CSS selector for the element to display in fullscreen. If omitted, the entire document enters fullscreen.
{{ stimulus_action('@pwa/fullscreen', 'request', 'click') }}Or for a specific element:
{{ stimulus_action('@pwa/fullscreen', 'request', 'click', {target: '#my-element'}) }}Fullscreen requests must be triggered by user interaction. Programmatic calls without user gestures will be rejected by the browser.
exit
exitExits fullscreen mode and returns to normal display.
{{ stimulus_action('@pwa/fullscreen', 'exit', 'click') }}Alternatively, users can press the Escape key to exit fullscreen mode (this is a browser feature, not controlled by the component).
Targets
None
Events
pwa--fullscreen:change
pwa--fullscreen:changeDispatched when fullscreen mode is toggled (entered or exited).
Payload: {fullscreen, element}
fullscreen(boolean):truewhen entering fullscreen,falsewhen exitingelement(Element): The element that entered fullscreen
Example:
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen, element } = event.detail;
if (fullscreen) {
console.log('Entered fullscreen for:', element);
// Update UI for fullscreen mode
document.body.classList.add('in-fullscreen');
} else {
console.log('Exited fullscreen');
// Restore normal UI
document.body.classList.remove('in-fullscreen');
}
});pwa--fullscreen:error
pwa--fullscreen:errorDispatched when an error occurs while entering or exiting fullscreen mode.
Payload: {element, error}
element(Element): The element that failed to enter fullscreenerror(Error): Error object containing details about the failure
Example:
document.addEventListener('pwa--fullscreen:error', (event) => {
const { element, error } = event.detail;
console.error('Fullscreen error for', element, ':', error);
// Show user-friendly error message
alert('Unable to enter fullscreen mode. Please try again.');
});Best Practices
User-initiated only: Always trigger fullscreen from user interactions (clicks, touches)
Provide exit option: Always offer a visible way to exit fullscreen
Handle Escape key: Document that users can press Escape to exit
Responsive design: Ensure your fullscreen content adapts to different screen sizes
Test on devices: Fullscreen behavior may vary across browsers and devices
Communicate state: Clearly indicate when fullscreen mode is active
Preserve content: Ensure fullscreen elements are properly restored when exiting
Common Use Cases
Media Player Controls
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen } = event.detail;
const controls = document.querySelector('.media-controls');
if (fullscreen) {
// Show minimal controls in fullscreen
controls.classList.add('minimal');
// Auto-hide controls after 3 seconds
setTimeout(() => {
controls.classList.add('hidden');
}, 3000);
} else {
// Show full controls in normal mode
controls.classList.remove('minimal', 'hidden');
}
});Dashboard Fullscreen
function toggleDashboardFullscreen() {
const controller = document.querySelector('[data-controller="@pwa/fullscreen"]');
const dashboard = document.getElementById('dashboard');
// Store current scroll position
const scrollPos = window.scrollY;
controller.dispatchEvent(new CustomEvent('request', {
detail: { params: { target: '#dashboard' } }
}));
// Restore scroll position when exiting
document.addEventListener('pwa--fullscreen:change', function handler(e) {
if (!e.detail.fullscreen) {
window.scrollTo(0, scrollPos);
document.removeEventListener('pwa--fullscreen:change', handler);
}
});
}Photo Viewer with Gestures
let touchStartX = 0;
let touchEndX = 0;
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen, element } = event.detail;
if (fullscreen && element.tagName === 'IMG') {
// Enable swipe gestures for navigation
element.addEventListener('touchstart', e => {
touchStartX = e.changedTouches[0].screenX;
});
element.addEventListener('touchend', e => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
}
});
function handleSwipe() {
if (touchEndX < touchStartX - 50) {
// Swipe left - next image
showNextImage();
}
if (touchEndX > touchStartX + 50) {
// Swipe right - previous image
showPreviousImage();
}
}Browser-Specific Considerations
Safari (iOS)
On iOS, only video elements can enter fullscreen (not other elements)
Fullscreen video is handled by the native player
Document-level fullscreen is not supported
Chrome/Edge
Full support for element and document fullscreen
Provides native fullscreen UI controls
Supports custom fullscreen styling with CSS
Firefox
Good support with vendor prefixes in older versions
Modern versions support standard Fullscreen API
CSS for Fullscreen Mode
You can style elements differently when in fullscreen using CSS:
/* Normal state */
.video-player {
max-width: 800px;
}
/* Fullscreen state */
.video-player:fullscreen {
width: 100vw;
height: 100vh;
background: black;
}
/* Vendor prefixes for older browsers */
.video-player:-webkit-full-screen {
width: 100vw;
height: 100vh;
}
.video-player:-moz-full-screen {
width: 100vw;
height: 100vh;
}Troubleshooting
Fullscreen not working
Common issues:
No user interaction: Fullscreen must be triggered by user gesture
Browser permissions: Some browsers block fullscreen by default
Iframe restrictions: Fullscreen may not work in iframes without proper attributes
Mobile Safari: Only video elements support fullscreen
Element not displaying correctly
Solutions:
Check CSS: Ensure fullscreen element has proper styling
Z-index issues: Fullscreen elements should have high z-index
Viewport units: Use
100vwand100vhfor full coverageAspect ratio: Maintain proper aspect ratios in fullscreen
Complete Example: Video Player
<div {{ stimulus_controller('@pwa/fullscreen') }}>
<div id="player-container" class="video-player">
<video id="video" src="/videos/sample.mp4"></video>
<div class="player-controls">
<button id="play-pause">▶️ Play</button>
<input type="range" id="progress" min="0" max="100" value="0">
<span id="time">0:00 / 0:00</span>
<button {{ stimulus_action('@pwa/fullscreen', 'request', 'click', {target: '#player-container'}) }}>
⛶ Fullscreen
</button>
</div>
</div>
</div>
<script>
const video = document.getElementById('video');
const playPauseBtn = document.getElementById('play-pause');
const progress = document.getElementById('progress');
const timeDisplay = document.getElementById('time');
playPauseBtn.addEventListener('click', () => {
if (video.paused) {
video.play();
playPauseBtn.textContent = '⏸️ Pause';
} else {
video.pause();
playPauseBtn.textContent = '▶️ Play';
}
});
video.addEventListener('timeupdate', () => {
const percent = (video.currentTime / video.duration) * 100;
progress.value = percent;
const current = formatTime(video.currentTime);
const total = formatTime(video.duration);
timeDisplay.textContent = `${current} / ${total}`;
});
progress.addEventListener('input', (e) => {
const time = (e.target.value / 100) * video.duration;
video.currentTime = time;
});
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
document.addEventListener('pwa--fullscreen:change', (event) => {
const { fullscreen } = event.detail;
const controls = document.querySelector('.player-controls');
if (fullscreen) {
controls.classList.add('fullscreen-controls');
video.play();
} else {
controls.classList.remove('fullscreen-controls');
}
});
</script>
<style>
.video-player {
position: relative;
max-width: 800px;
margin: 0 auto;
}
.video-player:fullscreen {
width: 100vw;
height: 100vh;
background: black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.video-player:fullscreen video {
width: 100%;
height: calc(100% - 60px);
}
.player-controls {
display: flex;
gap: 10px;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
}
.fullscreen-controls {
position: absolute;
bottom: 0;
width: 100%;
}
</style>Last updated
Was this helpful?