{"id":3827,"date":"2021-09-13T17:12:25","date_gmt":"2021-09-13T17:12:25","guid":{"rendered":"https:\/\/ionicframework.com\/blog\/?p=3827"},"modified":"2023-01-21T00:33:06","modified_gmt":"2023-01-21T05:33:06","slug":"building-with-stencil-audio-player-component","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component","title":{"rendered":"Building with Stencil: Audio Player Component"},"content":{"rendered":"<p>In this tutorial, we are going to build an audio player component using <a href=\"https:\/\/stenciljs.com\/\">Stencil<\/a>. You\u2019ll be introduced to many fundamental concepts in Stencil and by the end of the tutorial you\u2019ll have a foundational audio player component that you can customize for your own apps.<\/p>\n<p>Stencil is a great tool for building reusable web components and is especially suitable for building out design systems at scale. Stencil components can be incorporated into many front-end frameworks like React, Angular, and Vue\u2014or no framework at all. By building our audio player with Stencil, we\u2019ll have an incredibly versatile component that we can use anywhere.<\/p>\n<p><!--more--><\/p>\n<p>Here\u2019s the final audio player component we\u2019ll be building:<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/AudioPlayerComponent.png\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" style=\"--smush-placeholder-width: 309px; --smush-placeholder-aspect-ratio: 309\/179;\"><noscript><img decoding=\"async\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/AudioPlayerComponent.png\"><\/noscript><\/p>\n<p>Find all of the code for this tutorial at the <a href=\"https:\/\/github.com\/a-giuliano\/audio-player\">Stencil audio player component GitHub repository here<\/a>.<\/p>\n<h2>Set Up Your Stencil Project<\/h2>\n<p>To create a new Stencil project, we&#8217;ll want to open up the terminal and run the following command:<\/p>\n<pre><code class=\"language-bash\">npm init stencil\n<\/code><\/pre>\n<p>After running this command, you may be prompted to give permission to install the <code>create-stencil<\/code> package. If so, answer \u201cyes\u201d to the prompt. Next, we&#8217;ll be prompted for a starter. Select &#8220;component&#8221; as that&#8217;s what we&#8217;ll be building in this tutorial.<\/p>\n<pre><code class=\"language-bash\">? Pick a starter \u203a - Use arrow-keys. Return to submit.\n\n   app           Minimal starter for building a Stencil app or website\n\u276f  component     Collection of web components that can be used anywhere\n<\/code><\/pre>\n<p>Next you&#8217;ll be prompted for a project name. Feel free to name your project whatever you like. I named mine <code>audio-player-project<\/code>. Once you&#8217;ve named your project, you&#8217;re all set up and ready to create a component.<\/p>\n<h2>Generate a New Component<\/h2>\n<p>Once we&#8217;ve created the Stencil project and we&#8217;ve navigated inside the project directory, we can generate all of the boilerplate code for our component with the following command:<\/p>\n<pre><code class=\"language-bash\">npm run generate\n<\/code><\/pre>\n<p>When prompted for the component tag name, feel free to name it whatever you like. Just make sure that the name uses dash-case (includes a hyphen). We&#8217;ll be naming the component <code>audio-player<\/code>. After you name the component, press enter again to generate all of the additional files. These files are used for testing and styling. Finally, navigate to <code>src\/components\/audio-player\/audio-player.tsx<\/code> (this will be different if you&#8217;ve named your component something else). This <code>audio-player.tsx<\/code> file is the core of our component and we&#8217;ll also be using <code>audio-player.css<\/code> for styling.<\/p>\n<h2>Props and State<\/h2>\n<p>In order to build this component, we need to think of all the required elements. We want to be able to provide any title and audio source for the player. Therefore, we need to use the <a href=\"https:\/\/stenciljs.com\/docs\/properties\"><code>@Prop<\/code> decorator<\/a> to expose these properties.<\/p>\n<p>We also need a few pieces of state in our audio player. We want to know the total duration of the audio clip, the current time of the clip, and whether or not the audio is playing or paused. Because each of these aspects can change depending on how the user interacts with the component, we\u2019ll add them as pieces of state with the <a href=\"https:\/\/stenciljs.com\/docs\/state\"><code>@State<\/code> decorator<\/a>.<\/p>\n<p>Finally, we need one last piece of state that we\u2019ll use as a reference to our <code>audio<\/code> element in order to access certain properties of the audio clip. With all of that in mind, we can initialize our props and state.<\/p>\n<pre><code class=\"language-ts\">Export class AudioPlayer {\n  @Prop() title: string;\n  @Prop() src: string;\n\n  @State() isPlaying: boolean = false;\n  @State() duration: number = 0;\n  @State() currentTime: number = 0;\n  @State() audioPlayer: HTMLAudioElement;\n<\/code><\/pre>\n<h2>Rendering the Audio Player<\/h2>\n<p>Now that we have all of our properties and states, we can begin to incorporate them into our render function to display them in the component.<\/p>\n<pre><code class=\"language-jsx\">render() {\n  return (\n    &lt;div class=&quot;container&quot;&gt;\n      &lt;div class=&quot;title&quot;&gt;{this.title}&lt;\/div&gt;\n      &lt;div class=&quot;player&quot;&gt;\n        &lt;button class=&quot;play-button&quot;&gt;\n          {this.isPlaying ? &#039;Pause&#039; : &#039;Play&#039; }\n        &lt;\/button&gt;\n        {this.currentTime + &quot;\/&quot; + this.duration}\n        &lt;audio\n          src={this.src}\n          preload=&quot;metadata&quot;\n          ref={(el) =&gt; this.audioPlayer = el as HTMLAudioElement}\n        &gt;\n          Your browser does not support the HTML5 audio element\n        &lt;\/audio&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/code><\/pre>\n<p>Most of the component is simply displaying the values of our props and state. The play button uses conditional rendering to display \u201cplay\u201d or \u201cpause\u201d depending on whether or not the audio is playing. Most importantly, we have the <code>audio<\/code> element at the bottom. Naturally, we set the source to the value of the prop passed into the component. By setting the <code>preload<\/code> attribute to <code>metadata<\/code>, we are specifying that the browser should load the audio metadata on page load. Finally, we use the <code>ref<\/code> attribute to create a reference to the <code>audio<\/code> element.<\/p>\n<p>Of course, we\u2019ll need to pass in attribute values for our <code>audio-player<\/code> in our <code>index.html<\/code> file.<\/p>\n<pre><code class=\"language-html\">  &lt;audio-player title=&quot;My Audio Clip&quot; src=&quot;https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/Theme-Song-Ferdinand-Souvenir.mp3&quot; \/&gt;\n<\/code><\/pre>\n<p>Feel free to use whatever audio source you want here.<\/p>\n<h2>Playing Audio<\/h2>\n<p>Next, we want to add some functionality so we can actually play our audio. Luckily for us, our <code>audio<\/code> element has methods for doing just that. Using our reference to the <code>audio<\/code> element, and making sure to manage our <code>isPlaying<\/code> state, we can create a function to play and pause.<\/p>\n<pre><code class=\"language-ts\">togglePlay = () =&gt; {\n  if (this.isPlaying) {\n    this.audioPlayer.pause();\n    this.isPlaying = false;\n  } else {\n    this.audioPlayer.play();\n    this.isPlaying = true;\n  }\n}\n<\/code><\/pre>\n<p>Then call that function when our button is pressed.<\/p>\n<pre><code class=\"language-jsx\">&lt;button class=&quot;play-button&quot; onClick={this.togglePlay}&gt;\n  {this.isPlaying ? &#039;Pause&#039; : &#039;Play&#039; }\n&lt;\/button&gt;\n<\/code><\/pre>\n<h2>Audio Duration<\/h2>\n<p>Both our <code>duration<\/code> and <code>currentTime<\/code> states will be numbers representing time in seconds. We want to display these values to the user, but we want the time in minutes and seconds. Let\u2019s create a function that takes time in seconds and formats the time in a more human readable way.<\/p>\n<pre><code class=\"language-ts\">formatTime = (time: number) =&gt; {\n  const minutes = Math.floor(time \/ 60);\n  const seconds = Math.floor(time % 60).toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  return minutes + &quot;:&quot; + seconds;\n}\n<\/code><\/pre>\n<p><code>toLocaleString<\/code> is a convenient little method that allows us to prepend a 0 when the seconds value is a single digit. This way, one minute and three seconds is \u201c1:03\u201d instead of \u201c1:3\u201d.<\/p>\n<p>Now let\u2019s use this function to format our times.<\/p>\n<pre><code class=\"language-jsx\">{this.formatTime(this.currentTime) + &quot;\/&quot; + this.formatTime(this.duration)}\n<\/code><\/pre>\n<p>Now that duration and current time are initialized and formatted, let\u2019s actually set their values. First, we\u2019ll set the duration. This is a property that we can access on our <code>audioPlayer<\/code> element. However, we can only access it after our <code>audioPlayer<\/code> reference has been attached to our <code>audio<\/code> element and the audio metadata has loaded. We can wait for both of those events like so:<\/p>\n<pre><code class=\"language-ts\">@Watch(&#039;audioPlayer&#039;)\nwatchAudioPlayerHandler() {\n  this.audioPlayer.onloadedmetadata = () =&gt; {\n    this.duration = this.audioPlayer.duration;\n  }\n}\n<\/code><\/pre>\n<p>Here we use the <a href=\"https:\/\/stenciljs.com\/docs\/reactive-data\"><code>@Watch<\/code> decorator<\/a> which executes the attached function whenever the specified state changes. In our case, the <code>audioPlayer<\/code> state changes when it becomes a reference to the <code>audio<\/code> element. That change is our cue to grab the audio duration. To do that, we have to ensure the metadata has been loaded and is available, so we use the <code>onloadedmetadata<\/code> method.<\/p>\n<h2>Current Time<\/h2>\n<p>The <code>currentTime<\/code> is a little more complex because it is constantly changing. For such a situation we can leverage <code>requestAnimationFrame()<\/code> which allows us to make a request to the browser to execute a specific function before the next repaint. The function is passed to <code>requestAnimationFrame()<\/code> as a callback. Most importantly, if that function contains another call to <code>requestAnimationFrame()<\/code>, it will create an animation loop. We\u2019ll do this to continually increment our current time.<\/p>\n<pre><code class=\"language-ts\">incrementTime = () =&gt; {\n  this.currentTime = this.audioPlayer.currentTime;\n  this.stopId = requestAnimationFrame(this.incrementTime);\n}\n<\/code><\/pre>\n<p>You may be curious about <code>this.stopId<\/code>. This is a number that is returned by <code>requestAnimationFrame()<\/code> to identify the animation request. We can declare it towards the top of our component.<\/p>\n<pre><code class=\"language-ts\">private stopId: number;\n<\/code><\/pre>\n<p>And we can use it in our <code>togglePlay<\/code> function to stop the animation:<\/p>\n<pre><code class=\"language-ts\">togglePlay = () =&gt; {\n  if (this.isPlaying) {\n    this.audioPlayer.pause();\n    this.isPlaying = false;\n    cancelAnimationFrame(this.stopId);\n  } else {\n    this.audioPlayer.play();\n    this.isPlaying = true;\n    this.incrementTime();\n  }\n}\n<\/code><\/pre>\n<p>When we want to play the audio, we call our <code>incrementTime<\/code> function to start the animation loop, and when we pause, we call <code>cancelAnimationFrame<\/code> with our <code>stopId<\/code> to end the animation loop.<\/p>\n<h2>Make it Pretty<\/h2>\n<p>Our play\/pause button works well, but it doesn&#8217;t look great. To use icons instead of text, we must first create a new folder under <code>src<\/code> called <code>assets<\/code>. We then have to reference our <code>assets<\/code> directory in our component.<\/p>\n<pre><code class=\"language-ts\">@Component({\n  tag: &#039;audio-player&#039;,\n  styleUrl: &#039;audio-player.css&#039;,\n  assetsDirs: [&#039;assets&#039;],\n  shadow: true,\n})\n<\/code><\/pre>\n<p>Next, we\u2019ll add our <a href=\"https:\/\/github.com\/a-giuliano\/audio-player\/blob\/master\/src\/assets\/play.svg\">play<\/a> and <a href=\"https:\/\/github.com\/a-giuliano\/audio-player\/blob\/master\/src\/assets\/pause.svg\">pause<\/a> icons to our <code>assets<\/code> folder. Finally, we can use <code>getAssetPath()<\/code> in an <code>img<\/code> tag to display our icons.<\/p>\n<pre><code class=\"language-jsx\">&lt;div class=&quot;play-button&quot; onClick={this.togglePlay}&gt;\n  {\n    this.isPlaying\n      ? &lt;img src={getAssetPath(&quot;..\/..\/assets\/pause.svg&quot;)} \/&gt;\n      : &lt;img src={getAssetPath(&quot;..\/..\/assets\/play.svg&quot;)} \/&gt;\n  }\n&lt;\/div&gt;\n<\/code><\/pre>\n<p>To top it all off, we\u2019ll add some CSS in <code>audio-player.css<\/code>:<\/p>\n<pre><code class=\"language-css\">:host {\n  display: block;\n  font-family: sans-serif;\n}\n\n.container {\n  width: fit-content;\n  padding: 12px;\n  border-radius: 8px;\n  box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;\n}\n\n.title {\n  font-weight: bold;\n  margin-bottom: 8px;\n}\n\n.player {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.play-button {\n  width: 16px;\n}\n<\/code><\/pre>\n<p>And there you have it! We\u2019ve built the foundation of an audio player component that you can now add all kinds of exciting features and styles to. Our audio player is one example, but you can build any component you want with Stencil, like a <a href=\"https:\/\/ionicframework.com\/blog\/building-with-stencil-calendar-component\/\">calendar<\/a> or a <a href=\"https:\/\/ionicframework.com\/blog\/building-with-stencil-clock-component\/\">clock<\/a>. You can then use the components you build to create an entire design system that can be used across different frameworks. Needless to say, we\u2019re excited to see what you decide to create!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we are going to build an audio player component using Stencil. You\u2019ll be introduced to many fundamental concepts in Stencil and by the end of the tutorial you\u2019ll have a foundational audio player component that you can customize for your own apps. Stencil is a great tool for building reusable web components [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":3828,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"0","publish_post_category":"21","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"","discourse_permalink":"","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[223,124],"tags":[140,76,82],"class_list":["post-3827","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stencil","category-tutorials","tag-design-systems","tag-stencil","tag-web-components"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Building with Stencil: Audio Player Component - Ionic Blog<\/title>\n<meta name=\"description\" content=\"Stencil allows developers to build reusable web components that can be incorporated into front-end frameworks like React, Angular, and Vue.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building with Stencil: Audio Player Component\" \/>\n<meta property=\"og:description\" content=\"Stencil allows developers to build reusable web components that can be incorporated into front-end frameworks like React, Angular, and Vue.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-13T17:12:25+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-21T05:33:06+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1600\" \/>\n\t<meta property=\"og:image:height\" content=\"880\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Anthony Giuliano\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@a__giuliano\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Anthony Giuliano\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\"},\"author\":{\"name\":\"Anthony Giuliano\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/a3190e4d49187220d0c720f2ceab9b58\"},\"headline\":\"Building with Stencil: Audio Player Component\",\"datePublished\":\"2021-09-13T17:12:25+00:00\",\"dateModified\":\"2023-01-21T05:33:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\"},\"wordCount\":1230,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png\",\"keywords\":[\"Design Systems\",\"stencil\",\"web components\"],\"articleSection\":[\"Stencil\",\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\",\"url\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\",\"name\":\"Building with Stencil: Audio Player Component - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png\",\"datePublished\":\"2021-09-13T17:12:25+00:00\",\"dateModified\":\"2023-01-21T05:33:06+00:00\",\"description\":\"Stencil allows developers to build reusable web components that can be incorporated into front-end frameworks like React, Angular, and Vue.\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png\",\"width\":1600,\"height\":880},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building with Stencil: Audio Player Component\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/a3190e4d49187220d0c720f2ceab9b58\",\"name\":\"Anthony Giuliano\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/10\/anthony-giuliano-profile-cropped-150x150.jpeg\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/10\/anthony-giuliano-profile-cropped-150x150.jpeg\",\"caption\":\"Anthony Giuliano\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/anthonygiuliano1\/\",\"https:\/\/x.com\/a__giuliano\"],\"url\":\"https:\/\/ionic.io\/blog\/author\/anthonyionic-io\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building with Stencil: Audio Player Component - Ionic Blog","description":"Stencil allows developers to build reusable web components that can be incorporated into front-end frameworks like React, Angular, and Vue.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component","og_locale":"en_US","og_type":"article","og_title":"Building with Stencil: Audio Player Component","og_description":"Stencil allows developers to build reusable web components that can be incorporated into front-end frameworks like React, Angular, and Vue.","og_url":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component","og_site_name":"Ionic Blog","article_published_time":"2021-09-13T17:12:25+00:00","article_modified_time":"2023-01-21T05:33:06+00:00","og_image":[{"width":1600,"height":880,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png","type":"image\/png"}],"author":"Anthony Giuliano","twitter_card":"summary_large_image","twitter_creator":"@a__giuliano","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Anthony Giuliano","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component"},"author":{"name":"Anthony Giuliano","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/a3190e4d49187220d0c720f2ceab9b58"},"headline":"Building with Stencil: Audio Player Component","datePublished":"2021-09-13T17:12:25+00:00","dateModified":"2023-01-21T05:33:06+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component"},"wordCount":1230,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png","keywords":["Design Systems","stencil","web components"],"articleSection":["Stencil","Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component","url":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component","name":"Building with Stencil: Audio Player Component - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png","datePublished":"2021-09-13T17:12:25+00:00","dateModified":"2023-01-21T05:33:06+00:00","description":"Stencil allows developers to build reusable web components that can be incorporated into front-end frameworks like React, Angular, and Vue.","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png","width":1600,"height":880},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-audio-player-component#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Building with Stencil: Audio Player Component"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/a3190e4d49187220d0c720f2ceab9b58","name":"Anthony Giuliano","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/10\/anthony-giuliano-profile-cropped-150x150.jpeg","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/10\/anthony-giuliano-profile-cropped-150x150.jpeg","caption":"Anthony Giuliano"},"sameAs":["https:\/\/www.linkedin.com\/in\/anthonygiuliano1\/","https:\/\/x.com\/a__giuliano"],"url":"https:\/\/ionic.io\/blog\/author\/anthonyionic-io"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-audio-feature-image.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3827","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=3827"}],"version-history":[{"count":1,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3827\/revisions"}],"predecessor-version":[{"id":4717,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3827\/revisions\/4717"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/3828"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=3827"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=3827"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=3827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}