Showreel player
A video player mounted by one attribute on a thumbnail: a link to an mp4 around its picture, or a block that holds a video element.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialThe look of the preview is theshowreel-player-*classes of the paste. The code is longer than one Webflow Embed holds, so the paste brings two: this stylesheet and the settings are the first, the script of the next step the second. The first Embed holds the look of the word and of the player, and reads five variables,--showreel-player-ground,--showreel-player-ink,--showreel-player-accent,--showreel-player-padand--showreel-player-word-size: set them on the thumbnail, or on anything above it, in a rule of your own. The words take the typeface of the thumbnail. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Use it on your own elements
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the element on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-showreel-player Marks the thumbnail: a link to a video file around its picture, or a block that holds a video. It takes no value: leave the value field empty. The engine lays the film over the picture, adds the word, and builds the player at the first click. The settings below go on the same element. data-showreel-player-src On the thumbnail, with the address of the film as its value, when the thumbnail is neither a link to the file nor the holder of a video element. [ Optional ] data-showreel-player-title On the thumbnail, with a few words as its value: the name shown at the head of the player. Without it the name is the alt of the picture. [ Optional ] data-showreel-player-ready Written by the engine on the thumbnail once it is mounted, with data-showreel-player-hover while a mouse is over it and data-showreel-player-away while its film is in the player; the player carries data-showreel-player-state (opening, open, dragging, closing), data-showreel-player-ui while its words are shown and data-showreel-player-idle once they have stepped back. Never written by hand; the stylesheet reads them, and so can a rule of yours. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.Attribute Default What it is data-showreel-player-duration 1.15 The time the film takes to go from its thumbnail to the full screen, in seconds. The way back takes the same. data-showreel-player-follow 0.14 How closely the word keeps up with the pointer over the thumbnail, the share of the gap it closes each frame. data-showreel-player-fit auto How the film fills the screen once open. Options: auto, the film fills the screen when that cuts no more than an eighth of it, and is shown whole otherwise; contain, always whole, on the ground; cover, always edge to edge, cut where it must be. data-showreel-player-preview on Whether the thumbnail plays the film, muted and in a loop, while it is on screen. Options: on; off, the thumbnail shows the waiting picture until the click, and the file is not loaded before. data-showreel-player-sound on Whether the film opens with its sound. Options: on, the sound rises as the film opens; off, the film opens muted and the button offers the sound. data-showreel-player-restart off Whether opening sends the film back to its first frame. Options: off, the film goes on from the frame the thumbnail was showing, with no cut; on, it starts again from the beginning. data-showreel-player-loop off Whether the open film plays again when it ends. Options: off, at its end the film goes back to its thumbnail by itself; on, it plays again until it is closed. data-showreel-player-play Play The word on the thumbnail, and of the button while the film is paused. Options: any short word, in the language of the page: Lire, Abspielen. data-showreel-player-pause Pause The word of the button while the film plays. Options: any short word: Pause. data-showreel-player-mute Mute The word of the button that cuts the sound. Options: any short word: Couper. data-showreel-player-unmute Unmute The word of the button that gives the sound back. Options: any short word: Son. data-showreel-player-close Close The word of the button that closes the player. Options: any short word: Fermer.
Two files and their pictures (1), no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
ShowreelPlayer.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-showreel-player-duration 1.15 The time the film takes to go from its thumbnail to the full screen, in seconds. The way back takes the same. Quicker; under 0.7 the two beats, across then apart, read as one; 0 opens at once Slower and more shown; over 1.6 the player feels late on the click data-showreel-player-follow 0.14 How closely the word keeps up with the pointer over the thumbnail, the share of the gap it closes each frame. Lazier, the word drifts behind; under 0.06 it feels lost Tighter; 1 sticks the word to the pointer with no lag data-showreel-player-fit auto How the film fills the screen once open. Options: auto, the film fills the screen when that cuts no more than an eighth of it, and is shown whole otherwise; contain, always whole, on the ground; cover, always edge to edge, cut where it must be. data-showreel-player-preview on Whether the thumbnail plays the film, muted and in a loop, while it is on screen. Options: on; off, the thumbnail shows the waiting picture until the click, and the file is not loaded before. data-showreel-player-sound on Whether the film opens with its sound. Options: on, the sound rises as the film opens; off, the film opens muted and the button offers the sound. data-showreel-player-restart off Whether opening sends the film back to its first frame. Options: off, the film goes on from the frame the thumbnail was showing, with no cut; on, it starts again from the beginning. data-showreel-player-loop off Whether the open film plays again when it ends. Options: off, at its end the film goes back to its thumbnail by itself; on, it plays again until it is closed. data-showreel-player-play Play The word on the thumbnail, and of the button while the film is paused. Options: any short word, in the language of the page: Lire, Abspielen. data-showreel-player-pause Pause The word of the button while the film plays. Options: any short word: Pause. data-showreel-player-mute Mute The word of the button that cuts the sound. Options: any short word: Couper. data-showreel-player-unmute Unmute The word of the button that gives the sound back. Options: any short word: Son. data-showreel-player-close Close The word of the button that closes the player. Options: any short word: Fermer. -
Drive it from JavaScript
When a button elsewhere opens the film, or when the page follows what the visitor watched.const element = document.querySelector('[data-showreel-player]'); element.addEventListener('showreelplayer:shown', (e) => { console.log(e.detail); }); // Follow the film: an analytics call when it is opened, and when it is watched to the end. element.addEventListener('showreelplayer:shown', () => console.log('opened')); element.addEventListener('showreelplayer:ended', () => console.log('watched')); const player = ShowreelPlayer.mount(element); // the thumbnail auto() mounted, or a new one player.open(); // from a click handler, so the browser allows the sound // Once it is open: player.pause(), player.play(), player.mute(), player.seek(12) and player.close(). // When the thumbnail leaves the page: ShowreelPlayer.destroy(element); // removes the player, gives the markup back as it was
-
Fit it to your page
The thumbnail
- A link around a picture is the plainest form, and the one the Webflow paste uses:
<a href="https://example.com/reel.mp4" data-showreel-player><img src="https://example.com/poster.jpg" alt="The 2026 reel"></a>. The engine lays the film over the picture, edge to edge, and shows it once it has a frame. Without JavaScript the link opens the file. - **A block that holds a
video** works the same:data-showreel-playeron the block, thevideoinside with itssrcor itssourceelements and itsposter. Writecontrolson it: the engine takes the browser's bar off while it runs, and a page without JavaScript keeps a video that can be played. - Any shape. The film can be wide, square or upright, and the thumbnail any crop of it (
object-fit: cover, anobject-position, a small radius): the film leaves from exactly that window and opens to its whole shape. - The name at the head of the player is the
altof the picture, ordata-showreel-player-title="Your words". - The film of the preview is twelve silent seconds hosted by Moving parts, there to show the player at work: replace the address of the link with your own film, and the picture with its first frame.
- A film with no sound track has no Mute button. The engine reads it from the browser (
audioTracksin Safari,mozHasAudioin Firefox, the count of decoded audio in Chrome) and hides the button; a film with sound gets it back by itself. - Several players on a page each work on their own, each with its settings and colours. While one is open the thumbnails of the others stop playing.
The mouse, the finger, the keyboard
Under a mouse the word leaves its corner and trails the pointer, and the pointer itself is hidden over the thumbnail. On a touch screen there is no pointer to trail: the word stays in its corner and a tap opens.
In the player a click on the film pauses and plays; on a touch screen the first tap brings the words back when they have stepped away. The line can be clicked and dragged, and shows the time under the pointer. A drag up or down on the film closes it by hand: the band follows the drag, goes home when it is let go far enough, and opens again otherwise.
Tab reaches the thumbnail; Enter opens it, and Space too when it is not a link. In the player the focus is on Pause and Tab goes round Pause, Mute, the line and Close without leaving. Space and K pause and play, M cuts the sound, Left and Right move five seconds, Home and End go to the two ends, Escape closes, and the focus returns to the thumbnail.
The colours and the sizes
Five custom properties, set at zero specificity on the thumbnail. Give them your own values on the thumbnail or on anything above it; the player, which is added at the end of the page, reads them from its thumbnail each time it opens, and takes the typeface of the word.
--showreel-player-ground: what shows around a film that does not fill the screen, warm black in the preview.--showreel-player-ink: the word, the line and the words of the player.--showreel-player-accent: a word under the pointer, and the focus ring.--showreel-player-pad: the margin of the player, and the corner the word rests in.--showreel-player-word-size: the size of the word on the thumbnail.
From JavaScript
ShowreelPlayer.mount(element, overrides)returns the instance of a thumbnail, mounting it if it was not:{ element, settings, video, state(), open(options), close(options), play(), pause(), toggle(), mute(value), seek(seconds), refresh(), destroy() }.opentakes{ instant: true }to skip the trip, or{ hold: 0.3 }to stop it at that share of the way, for a still;close()goes on from there.ShowreelPlayer.auto(root)mounts every marked thumbnail insideroot, and runs once on its own;ShowreelPlayer.destroy(element)gives the markup back.- Events, all bubbling from the thumbnail:
showreelplayer:ready, fired during the mount, so before any listener added after the script tag;showreelplayer:openas the film leaves its thumbnail;showreelplayer:shownonce it fills the screen;showreelplayer:playandshowreelplayer:pausewhile it is open, with{ time };showreelplayer:endedat its last frame;showreelplayer:closeonce it is back in its thumbnail. - A film opened from code, with no click behind it, may be refused its sound by the browser: it then opens muted and the button offers it.
- **Under
prefers-reduced-motion: reduce** the thumbnail does not play by itself, the word sticks to the pointer with no lag, and the player opens and closes at once. - Without JavaScript the thumbnail is the page's own link or video.
- The film and the words of the demo are the demo's: on a real page the film, its picture and its name are the user's own, or asked for.
- A link around a picture is the plainest form, and the one the Webflow paste uses:
-
Avoid the pitfalls
- The host of the film must answer byte ranges. Every real host does (a CDN, Cloudflare, S3, Vimeo's file links); a bare development server often does not, and then the line shows the time but cannot be clicked or dragged, and Safari will not play the film at all. The engine says so in the console: if the line does nothing under your pointer, look there first.
- Webflow does not host an mp4 in its Assets panel. Give the link the address of the file where it is hosted. A Webflow Background Video works as the film of a marked block, but Webflow strips its sound.
- The picture must fill the link: the film the engine makes covers the whole marked element. Give the element its size, and the picture
width: 100%; height: 100%; object-fit: cover. - **The attribute goes on the block or the link, not on the
video**: the word needs a box to live in. The engine says so and leaves the video alone. - **The marked element becomes
position: relative**, at zero specificity: a rule of the page that positions it wins. - **An
overflow: hiddenthumbnail cuts the word at its edges**, which suits a framed picture; take it off to let the word cross the edge. - **The player is added at the end of
body**, in a nativedialog, so a rule of the page that styles everydialogor everybuttonreaches it. Its own classes all start withshowreel-player-. - The stylesheet places the player. Without
showreel-player.cssthe word is not placed and the film has no ground, and the engine says so in the console. - The page behind is held still by
overflow: hiddenon thehtmlelement, with a padding the width of the scrollbar so nothing jumps. - On an iPhone the volume of a video belongs to the device: the sound starts at once instead of rising.
- In React or any framework that owns the DOM, mount in an effect and call
destroy()in its cleanup. The video element is moved to the dialog while the film is open and put back on close.
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Showreel player is a site utility component for Webflow and vanilla JavaScript, with no library. Also called video lightbox, showreel video player or play cursor video.
A video player mounted by one attribute on a thumbnail: a link to an mp4 around its picture, or a block that holds a video element. The thumbnail plays muted, in a loop, only while it is on screen, and carries one word, Play, at rest in its corner. Under a mouse the word leaves the corner and trails the pointer with a little lag; on a touch screen it stays where it is and a tap opens. On a click the very same video element leaves the page for the player without a cut or a reload: it first widens across the page as a band, at the height of the thumbnail, then the band opens up and down to the full screen and the crop of the thumbnail opens to the whole film, while the sound rises with it when the film has one. The word travels with the film: it flies from the pointer to the foot of the screen, shrinks, turns from Play to Pause and lands as the button. The controls are words, Pause, Mute, the time and Close, over one thin line that shows the time and can be dragged; they step back after a moment without a move. Closing plays it all backwards from wherever it is, a drag up or down closes by hand, and the film ends by going home on its own. A native dialog: focus kept inside, Escape, Space, arrows, M, the page held still, the focus given back to the thumbnail. Any film ratio, any thumbnail crop, several players on a page. Reduced motion respected. No library. Pattern type video lightbox, showreel, video modal.
Updated
Questions
Paste the section, select the Link Block of the thumbnail and give its link the address of your mp4. The Image inside is the picture that waits for the film. The attribute data-showreel-player is already on the link, and the code arrives as two Embeds with the paste.
Anywhere that serves the file directly and answers byte ranges, which every real host does: a CDN, Cloudflare R2, S3, or the direct file link of a paid Vimeo plan. The link of the thumbnail points at that address. If the time line does nothing under your pointer, the host is not answering byte ranges, and the console says so.
No. The player moves the very same video element from the page to the top of the screen, so the film goes on from the frame the thumbnail was showing. Set data-showreel-player-restart to on to start it again from the beginning instead.
The word rests in a corner of the thumbnail. Under a mouse it leaves the corner and trails the pointer with a little lag, set by data-showreel-player-follow. On a touch screen there is no pointer to trail: the word stays in its corner and a tap opens the film.
The thumbnail plays muted, in a loop, and only while it is on screen, which browsers allow. The sound comes in with the click that opens the film, rising as it opens. A film with no sound track has no Mute button, and data-showreel-player-sound set to off opens any film muted.
Yes. It opens in a native dialog: Enter opens it from the thumbnail, the focus stays among Pause, Mute, the time line and Close, Space and K pause, M mutes, Left and Right move five seconds, Escape closes, and the focus returns to the thumbnail. Under reduced motion the thumbnail does not play by itself and the film opens at once.
Yes, any shape, and the thumbnail can be any crop of it. The film fills the screen when that cuts no more than an eighth of it and is shown whole on a dark ground otherwise; data-showreel-player-fit set to contain or cover forces one or the other.