How to make Music Player In ReactJs :-
Hello friend's in this post we know about how to create an reactjs music player web app.
this source code form codepen.
DEMO
Step 1 :) Add HTML
App.js file
function App() {
return (
<>
<div id="root"></div>
<a target="_blank" title="instagram/web__addict" href="https://www.instagram.com/web__addict/"><i class="fab fa-instagram"></i></a>
</>
);
}
export default App;
Step 2 :) Add CSS
style.css
@import url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css);
@import url(https://fonts.googleapis.com/css?family=Rubik:300,400,500,700&display=swap);
@import url(https://cdnjs.cloudflare.com/ajax/libs/mediaelement/4.2.11/mediaelementplayer.min.css);
body {
font-family: "Rubik", sans-serif;
color: #071739;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background: #000;
}
body h1 {
font-size: 36px;
margin-bottom: 0;
}
body .card {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
max-width: 371px;
padding: 20px 5px;
margin-top: 40px;
border-radius: 20px;
color: #fff;
font-weight: 100;
box-shadow: 0px 0px 70px 0px #274684;
background: #071739;
overflow: hidden;
}
body .card .current-song {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 20px 0px;
border-radius: 20px;
color: #071739;
background: #fff;
}
body .card .current-song audio {
display: none;
}
body .card .current-song .img-wrap {
position: relative;
margin: 0 auto;
width: 270px;
height: 200px;
overflow: hidden;
border-radius: 20px;
box-shadow: 0px 10px 40px 0px rgba(39, 70, 132, 0.7);
}
body .card .current-song .img-wrap img {
width: 100%;
height: 100%;
}
body .card .current-song .song-name {
margin-top: 30px;
font-size: 22px;
}
body .card .current-song .song-autor {
color: #709fdc;
}
body .card .current-song .time {
display: flex;
justify-content: space-between;
margin-top: 10px;
width: 240px;
}
body .card .current-song #timeline {
position: relative;
margin: 0 auto;
width: 240px;
height: 5px;
background: #709fdc;
border-radius: 5px;
cursor: pointer;
}
body .card .current-song #timeline:hover .hover-playhead {
opacity: 1;
}
body .card .current-song #timeline:hover .hover-playhead::before {
opacity: 1;
}
body .card .current-song #timeline:hover .hover-playhead::after {
opacity: 1;
}
body .card .current-song #timeline #playhead {
position: relative;
z-index: 2;
width: 0;
height: 5px;
border-radius: 5px;
background: #071739;
}
body .card .current-song #timeline .hover-playhead {
position: absolute;
z-index: 1;
top: 0;
width: 0;
height: 5px;
opacity: 0;
border-radius: 5px;
background: #274684;
transition: opacity 0.3s;
}
body .card .current-song #timeline .hover-playhead::before {
opacity: 0;
content: attr(data-content);
display: block;
position: absolute;
top: -30px;
right: -23px;
width: 40px;
padding: 3px;
text-align: center;
color: white;
background: #274684;
border-radius: calc( 20px - 12px);
}
body .card .current-song #timeline .hover-playhead::after {
opacity: 0;
content: "";
display: block;
position: absolute;
top: -8px;
right: -8px;
border-top: 8px solid #274684;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
}
body .card .current-song .controls {
margin-top: 10px;
}
body .card .current-song .controls button, .down-btn {
color: #071739;
border-radius: 50%;
margin: 15px;
font-size: 18px;
text-align: center;
transition: 0.2s;
cursor: pointer;
border: none;
background: 0;
}
body .card .current-song .controls button:focus {
outline: none;
}
body .card .current-song .controls button.play {
width: 50px;
height: 50px;
border: 1px solid #e2e2e2;
}
body .card .current-song .controls button.play:hover {
left: 0;
box-shadow: 0px 0px 15px 0px rgba(39, 70, 132, 0.7);
}
body .card .current-song .controls button.play .fa-play {
transform: translateX(2px);
}
body .card .current-song .controls button.prev-next,.down-btn {
width: 35px;
height: 35px;
}
body .card .current-song .controls button.prev-next:hover {
transform: scale(1.2);
}
body .card .play-list {
display: flex;
flex-direction: column;
padding: 10px;
height: 180px;
overflow-y: scroll;
}
body .card .play-list .track {
display: flex;
align-items: center;
margin-bottom: 10px;
border-radius: calc( 20px - 10px);
border: 1px solid transparent;
transition: 0.3s;
cursor: pointer;
}
body .card .play-list .track:hover {
background: #274684;
border-color: #274684;
position: relative;
}
body .card .play-list .track.current-audio {
background: #274684;
box-shadow: 0px 0px 15px 0px #274684;
}
body .card .play-list .track.play-now {
background: #274684;
box-shadow: 0px 0px 15px 0px #274684;
position: relative;
}
body .card .play-list .track.play-now:after {
content: "";
display: block;
position: absolute;
left: 17px;
width: 57px;
height: 57px;
border-radius: calc( 20px - 10px);
font-size: 16px;
-webkit-animation: play 2s linear infinite;
animation: play 2s linear infinite;
background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='iso-8859-1'%3F%3E%3C!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3Csvg version='1.1' id='Capa_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 56 56' style='enable-background:new 0 0 56 56;' xml:space='preserve'%3E%3Cpath style='fill:%23071739;' d='M47.799,8.201c-10.935-10.935-28.663-10.935-39.598,0c-10.935,10.935-10.935,28.663,0,39.598 c10.935,10.935,28.663,10.935,39.598,0C58.734,36.864,58.734,19.136,47.799,8.201z M32.95,32.95c-2.734,2.734-7.166,2.734-9.899,0 c-2.734-2.734-2.734-7.166,0-9.899s7.166-2.734,9.899,0S35.683,30.216,32.95,32.95z'/%3E%3Cpath style='fill:%23E7ECED;' d='M35.778,20.222c-4.296-4.296-11.261-4.296-15.556,0c-4.296,4.296-4.296,11.261,0,15.556 c4.296,4.296,11.261,4.296,15.556,0C40.074,31.482,40.074,24.518,35.778,20.222z M30.121,30.121c-1.172,1.172-3.071,1.172-4.243,0 s-1.172-3.071,0-4.243s3.071-1.172,4.243,0S31.293,28.95,30.121,30.121z'/%3E%3Cg%3E%3Cpath style='fill:%23709fdc;' d='M35.778,35.778c-0.76,0.76-1.607,1.378-2.504,1.87l8.157,14.92c2.284-1.25,4.434-2.835,6.368-4.769 c1.934-1.934,3.519-4.084,4.769-6.368l-14.92-8.157C37.157,34.172,36.538,35.018,35.778,35.778z'/%3E%3Cpath style='fill:%23709fdc;' d='M20.222,20.222c0.76-0.76,1.607-1.378,2.504-1.87l-8.157-14.92c-2.284,1.25-4.434,2.835-6.368,4.769 s-3.519,4.084-4.769,6.368l14.92,8.157C18.843,21.828,19.462,20.982,20.222,20.222z'/%3E%3C/g%3E%3C/svg%3E");
}
body .card .play-list .track.play-now .track-img {
filter: opacity(70%);
}
body .card .play-list .track .track-img {
width: 90px;
border-radius: calc( 20px - 10px);
}
body .card .play-list .track .track-discr {
margin-left: 15px;
display: flex;
flex-direction: column;
min-width: 190px;
}
body .card .play-list .track .track-discr .track-name {
font-size: 17px;
margin-top: 8px;
}
body .card .play-list .track .track-discr .track-author {
margin-top: 8px;
font-weight: 300;
color: #709fdc;
}
body .card .play-list .track .track-duration {
min-width: 40px;
margin-left: 10px;
margin-right: 10px;
font-weight: 500;
}
.fa-instagram {
position: absolute;
color: #071739;
top: 3%;
right: 2%;
font-size: 38px;
}
.fa-instagram:hover {
font-size: 42px;
color: #fff;
transition: all 0.1s linear;
cursor: pointer;
}
.play-list::-webkit-scrollbar {
width: 5px;
}
.play-list::-webkit-scrollbar-thumb {
background: #fff;
border-radius: 5px;
}
.play-list::-webkit-scrollbar-track {
background: #071739;
}
@-webkit-keyframes play {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes play {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Step 3 ) add File CardProfile.js
import './player.css'
class CardProfile extends React.Component {
state = {
index: 3,
currentTime: '0:00',
musicList: [{name:'Nice piano and ukulele', author: 'Royalty', img: 'https://www.bensound.com/bensound-img/buddy.jpg', audio:'https://www.bensound.com/bensound-music/bensound-buddy.mp3', duration: '2:02'},
{name:'Gentle acoustic', author: 'Acoustic', img: 'https://www.bensound.com/bensound-img/sunny.jpg', audio:'https://www.bensound.com//bensound-music/bensound-sunny.mp3', duration: '2:20'},
{name:'Corporate motivational', author: 'Corporate', img: 'https://www.bensound.com/bensound-img/energy.jpg', audio:'https://www.bensound.com/bensound-music/bensound-energy.mp3', duration: '2:59'},
{name:'Slow cinematic', author: 'Royalty', img: 'https://www.bensound.com/bensound-img/slowmotion.jpg', audio:'https://www.bensound.com/bensound-music/bensound-slowmotion.mp3', duration: '3:26'}],
pause: false,
};
componentDidMount() {
this.playerRef.addEventListener("timeupdate", this.timeUpdate, false);
this.playerRef.addEventListener("ended", this.nextSong, false);
this.timelineRef.addEventListener("click", this.changeCurrentTime, false);
this.timelineRef.addEventListener("mousemove", this.hoverTimeLine, false);
this.timelineRef.addEventListener("mouseout", this.resetTimeLine, false);
}
componentWillUnmount() {
this.playerRef.removeEventListener("timeupdate", this.timeUpdate);
this.playerRef.removeEventListener("ended", this.nextSong);
this.timelineRef.removeEventListener("click", this.changeCurrentTime);
this.timelineRef.removeEventListener("mousemove", this.hoverTimeLine);
this.timelineRef.removeEventListener("mouseout", this.resetTimeLine);
}
changeCurrentTime = (e) => {
const duration = this.playerRef.duration;
const playheadWidth = this.timelineRef.offsetWidth;
const offsetWidht = this.timelineRef.offsetLeft;
const userClickWidht = e.clientX - offsetWidht;
const userClickWidhtInPercent = (userClickWidht*100)/playheadWidth;
this.playheadRef.style.width = userClickWidhtInPercent + "%";
this.playerRef.currentTime = (duration * userClickWidhtInPercent)/100;
}
hoverTimeLine = (e) => {
const duration = this.playerRef.duration;
const playheadWidth = this.timelineRef.offsetWidth
const offsetWidht = this.timelineRef.offsetLeft;
const userClickWidht = e.clientX - offsetWidht;
const userClickWidhtInPercent = (userClickWidht*100)/playheadWidth;
if(userClickWidhtInPercent <= 100){
this.hoverPlayheadRef.style.width = userClickWidhtInPercent + "%";
}
const time = (duration * userClickWidhtInPercent)/100;
if( (time >=0) && (time <= duration)){
this.hoverPlayheadRef.dataset.content = this.formatTime(time);
}
}
resetTimeLine = () => {
this.hoverPlayheadRef.style.width = 0;
}
timeUpdate = () => {
const duration = this.playerRef.duration;
const timelineWidth = this.timelineRef.offsetWidth - this.playheadRef.offsetWidth;
const playPercent = 100 * (this.playerRef.currentTime / duration);
this.playheadRef.style.width = playPercent + "%";
const currentTime = this.formatTime(parseInt(this.playerRef.currentTime));
this.setState({
currentTime
});
}
formatTime = (currentTime) =>{
const minutes = Math.floor(currentTime / 60);
let seconds = Math.floor(currentTime % 60);
seconds = (seconds >= 10) ? seconds : "0" + seconds % 60;
const formatTime = minutes + ":" + seconds
return formatTime;
}
updatePlayer = () =>{
const { musicList, index } = this.state;
const currentSong = musicList[index];
const audio = new Audio(currentSong.audio);
this.playerRef.load();
}
nextSong = () => {
const { musicList, index, pause } = this.state;
this.setState({
index: (index + 1) % musicList.length
});
this.updatePlayer();
if(pause){
this.playerRef.play();
}
};
prevSong = () => {
const { musicList, index, pause } = this.state;
this.setState({
index: (index + musicList.length - 1) % musicList.length
});
this.updatePlayer();
if(pause){
this.playerRef.play();
}
};
playOrPause = () =>{
const { musicList, index, pause } = this.state;
const currentSong = musicList[index];
const audio = new Audio(currentSong.audio);
if( !this.state.pause ){
this.playerRef.play();
}else{
this.playerRef.pause();
}
this.setState({
pause: !pause
})
}
clickAudio = (key) =>{
const { pause } = this.state;
this.setState({
index: key
});
this.updatePlayer();
if(pause){
this.playerRef.play();
}
}
render() {
const { musicList, index, currentTime, pause } = this.state;
const currentSong = musicList[index];
return (
<div className="card">
<div className="current-song">
<audio ref={ref => this.playerRef = ref}>
<source src={ currentSong.audio } type="audio/ogg"/>
Your browser does not support the audio element.
</audio>
<div className="img-wrap">
<img src={ currentSong.img }/>
</div>
<span className="song-name">{ currentSong.name }</span>
<span className="song-autor">{ currentSong.author }</span>
<div className="time">
<div className="current-time">{ currentTime }</div>
<div className="end-time">{ currentSong.duration }</div>
</div>
<div ref={ref => this.timelineRef = ref} id="timeline">
<div ref={ref => this.playheadRef = ref} id="playhead"></div>
<div ref={ref => this.hoverPlayheadRef = ref} class="hover-playhead" data-content="0:00"></div>
</div>
<div className="controls">
<button onClick={this.prevSong} className="prev prev-next current-btn"><i className="fas fa-backward"></i></button>
<button onClick={this.playOrPause} className="play current-btn">
{
(!pause) ? <i className="fas fa-play"></i>
:<i class="fas fa-pause"></i>
}
</button>
<button onClick={this.nextSong} className="next prev-next current-btn"><i className="fas fa-forward"></i></button>
</div>
</div>
<div className="play-list" >
{musicList.map( (music, key=0) =>
<div key={key}
onClick={()=>this.clickAudio(key)}
className={"track " +
(index === key && !pause ?'current-audio':'') +
(index === key && pause ?'play-now':'')} >
<img className="track-img" src={music.img}/>
<div className="track-discr" >
<span className="track-name" >{music.name}</span>
<span className="track-author" >{music.author}</span>
</div>
<span className="track-duration" >
{(index === key)
?currentTime
:music.duration
}
</span>
</div>
)}
</div>
</div>
)
}
}
ReactDOM.render(
<CardProfile/>,
document.getElementById('root')
)
2 comments