Back to all posts
A row of animated videos
3 HTML5 videos in a row with animation and autoplay on hover. On click opens a full YouTube video in a dialog

1// components/html5Video.js
2
3const Html5Video = ({
4 item: { coverImg, title, description, videoUrl, mp4Video, webmVideo },
5 showFullVideo,
6}) => {
7 const theme = useTheme();
8 const isMobile = useMediaQuery(theme.breakpoints.down('md'));
9 const hasTouch = isTouchDevice();
10
11 const playerRef = useRef();
12 const coverRef = useRef();
13 const playerContainerRef = useRef();
14
15 // currentTime
16 const playOnHover = () => {
17 // 1. hideCoverImg
18 coverRef.current.style.zIndex = 0;
19 coverRef.current.style.opacity = 0;
20 // 2. animate container
21 playerContainerRef.current.style.width = ACTIVE_VIDEO_WIDTH;
22 // 3. play video
23 playerRef.current.play();
24 };
25 const onMouseLeave = () => {
26 // 1. pause video and reset time
27 playerRef.current.pause();
28 playerRef.current.currentTime = 0;
29 // 2. container
30 playerContainerRef.current.style.width = INITIAL_VIDEO_WIDTH;
31 // 3. show cover img
32 coverRef.current.style.zIndex = 1;
33 coverRef.current.style.opacity = 1;
34 };
35
36 return (
37 <Box
38 ref={playerContainerRef}
39 sx={styles.videoBlock}
40 onMouseEnter={isMobile || hasTouch ? undefined : () => playOnHover()}
41 onMouseLeave={isMobile || hasTouch ? undefined : () => onMouseLeave()}
42 onClick={() => showFullVideo(videoUrl)}>
43 <Box
44 ref={coverRef}
45 sx={{
46 ...styles.coverBlock,
47 backgroundImage: `url(${coverImg || videoUrl})`,
48 }}>
49 <Box sx={styles.title}>{title}</Box>
50 <Box sx={styles.description}>{description}</Box>
51 </Box>
52
53 {!isMobile && !hasTouch && (
54 <Box sx={styles.videoWrapper}>
55 <video
56 ref={playerRef}
57 playsInline
58 loop
59 muted
60 preload='true'
61 style={{
62 width: '100%',
63 height: '100%',
64 position: 'absolute',
65 objectFit: 'cover',
66 top: '50%',
67 left: '50%',
68 transform: 'translate(-50%,-50%)',
69 borderRadius: '9px',
70 }}>
71 {mp4Video && <source type='video/mp4' src={mp4Video} />}
72 {webmVideo && <source type='video/webm' src={webmVideo} />}
73 Your browser does not support HTML5 video tag.
74 </video>
75 </Box>
76 )}
77 </Box>
78 );
79};
80
81Html5Video.propTypes = {
82 item: PropTypes.object.isRequired,
83};
84
85export default Html5Video;
1// components/youtubeEmbed.js
2
3const YoutubeEmbed = ({ embedId }) => (
4 <Box sx={styles.videoContainer}>
5 <iframe
6 src={`https://www.youtube.com/embed/${embedId}`}
7 frameBorder='0'
8 allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
9 allowFullScreen
10 />
11 </Box>
12);
13
14YoutubeEmbed.propTypes = {
15 embedId: PropTypes.string.isRequired,
16};
17
18export default YoutubeEmbed;
1// containers/videoGallery.js
2
3const VideoGallery = ({ items = [] }) => {
4 const theme = useTheme();
5 const isMobile = useMediaQuery(theme.breakpoints.down('md'));
6
7 const [fullVideo, setFullVideo] = useState(null);
8 const showFullVideo = (embedCode) => {
9 setFullVideo(embedCode);
10 };
11 const closeFullVideo = () => {
12 setFullVideo(null);
13 };
14
15 return (
16 <Box sx={styles.section} component='section'>
17 <Box sx={styles.container}>
18 <Box sx={styles.content}>
19 {items.map((item) => {
20 return (
21 <Html5Video
22 key={item.title}
23 item={item}
24 showFullVideo={showFullVideo}
25 />
26 );
27 })}
28 </Box>
29 </Box>
30 {!!fullVideo && (
31 <Dialog
32 fullScreen={isMobile}
33 fullWidth
34 maxWidth='md'
35 open
36 onClose={closeFullVideo}
37 sx={styles.dialog}>
38 {isMobile && (
39 <IconButton sx={styles.closeBtn} onClick={closeFullVideo}>
40 <CloseIcon />
41 </IconButton>
42 )}
43 <YoutubeEmbed embedId={fullVideo} />
44 </Dialog>
45 )}
46 </Box>
47 );
48};
49
50VideoGallery.propTypes = {
51 items: PropTypes.array.isRequired,
52};
53
54export default VideoGallery;