{"id":3839,"date":"2021-09-22T21:08:09","date_gmt":"2021-09-22T21:08:09","guid":{"rendered":"https:\/\/ionicframework.com\/blog\/?p=3839"},"modified":"2023-01-21T00:32:59","modified_gmt":"2023-01-21T05:32:59","slug":"building-with-stencil-countdown-tracker","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker","title":{"rendered":"Building with Stencil: Countdown Tracker"},"content":{"rendered":"<p>In this tutorial, we are going to build a countdown tracker component using <a href=\"https:\/\/stenciljs.com\/\">Stencil<\/a>. Countdown trackers are a great way to both inform your users of an event, as well as generate excitement around the event. By the end of this tutorial you\u2019ll have a countdown tracker component that you can reuse and 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 <a href=\"https:\/\/reactjs.org\/\">React<\/a>, <a href=\"https:\/\/angular.io\/\">Angular<\/a>, and <a href=\"https:\/\/vuejs.org\/\">Vue<\/a>\u2014or no framework at all. By building our countdown tracker 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 countdown tracker component we\u2019ll be building:<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/countdown-tracker.png\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" style=\"--smush-placeholder-width: 1268px; --smush-placeholder-aspect-ratio: 1268\/164;\"><noscript><img decoding=\"async\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/countdown-tracker.png\"><\/noscript><\/p>\n<p>You can actually see this component in action on the <a href=\"https:\/\/ionic.io\/events\">Ionic events site<\/a>! We&#8217;re using it to count down to the Ionic Launch Event on September 28!<\/p>\n<p>You can find all the code for this tutorial at the <a href=\"https:\/\/github.com\/a-giuliano\/countdown-tracker\">Stencil countdown tracker component GitHub repository here<\/a>.<\/p>\n<p>This tutorial assumes that you already have a Stencil project set up. If you don&#8217;t already have a stencil project, check out the <a href=\"https:\/\/stenciljs.com\/docs\/getting-started\">Stencil docs<\/a> to get started.<\/p>\n<h2>Props and State<\/h2>\n<p>In order to build a countdown tracker, we need to know two critical data points: what date and time are we counting down to, and how much time is left between that time and now. The target date and time needs to be provided to us by the user, so we will accept it as a <code>@Prop<\/code> called <code>endDate<\/code> with a type of <code>string<\/code>. This string will need to be in <a href=\"https:\/\/www.w3.org\/TR\/NOTE-datetime\">ISO format<\/a> so it can be converted into a JavaScript <code>Date<\/code> object later. We are going to display the time between the <code>endDate<\/code> and now in terms of days, hours, minutes, and seconds. Because these values will change over time and we want to update our countdown tracker each time they change, we need to use <code>@State<\/code> for each of these values. We&#8217;ll initialize them all to be &#8220;00&#8221; to start.<\/p>\n<pre><code class=\"language-ts\">export class CountdownTracker {\n  @Prop() endDate: string;\n\n  @State() days: string = &#039;00&#039;;\n  @State() hours: string = &#039;00&#039;;\n  @State() minutes: string = &#039;00&#039;;\n  @State() seconds: string = &#039;00&#039;;\n<\/code><\/pre>\n<h2>Initializing Our End Date<\/h2>\n<p>Because the <code>endDate<\/code> prop is provided as a string, we need to convert it to a JavaScript <code>Date<\/code> object in order to perform operations that will help us determine the time between the <code>endDate<\/code> and now. To do that, we can create a new <code>Date<\/code> object and pass it the <code>endDate<\/code> string we received as a property. Then, we can assign that value to a private variable called <code>endDateObj<\/code> so we can reference it later. We need to be sure to do this assignment in the <code>componentWillLoad()<\/code> lifecycle method so we have access to it when the countdown tracker is connected to the DOM.<\/p>\n<pre><code class=\"language-ts\">private endDateObj: Date;\n\ncomponentWillLoad() {\n  this.endDateObj = new Date(this.endDate);\n}\n<\/code><\/pre>\n<h2>Time Conversions<\/h2>\n<p>The core functionality of our countdown tracker is continuously calculating the time between the current date and time and the <code>endDate<\/code>. Fortunately, the JavaScript <code>Date<\/code> object has a useful function, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Date\/getTime\"><code>getTime()<\/code><\/a>, that can help us do exactly that. <code>getTime()<\/code> returns the number of milliseconds between the given <code>Date<\/code> object and January 1, 1970 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Unix_time\">Unix Epoch<\/a>). Since <code>getTime()<\/code> returns a number, we can use it to perform date arithmetic. We can calculate the remaining time until the <code>endDate<\/code> by subtracting the current time, <code>new Date()<\/code>, from the <code>endDate<\/code>. This will give us the remaining time in milliseconds, which we can convert into days, hours, minutes, and seconds.<\/p>\n<pre><code class=\"language-ts\">tick() {\n  \/\/ example value: 80834343, time in milliseconds between endDate and now\n  const timeRemaining = this.endDateObj.getTime() - new Date().getTime();\n\n  this.seconds = Math.floor((timeRemaining \/ 1000) % 60)\n                 .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  this.minutes = Math.floor((timeRemaining \/ (1000 * 60)) % 60)\n                 .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  this.hours = Math.floor((timeRemaining \/ (1000 * 60 * 60)) % 24)\n               .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  this.days = Math.floor((timeRemaining \/ (24 * 60 * 60 * 1000)) % 30)\n              .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n}\n<\/code><\/pre>\n<p>Let&#8217;s take a look at how we convert the <code>timeRemaining<\/code> in milliseconds to days, hours, minutes, and seconds. First, to convert the <code>timeRemaining<\/code> to seconds, we divide it by 1000 as there are 1000 milliseconds in a second. We could then convert this to minutes, by dividing by 60, but there would be some seconds remaining. Before we convert to minutes, we want to capture those remaining seconds. To do this, we can use the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/Remainder\">remainder operator<\/a> to get the remaining seconds after dividing the total seconds by 60, as there are 60 seconds in a minute. A similar procedure is used for each of the other values. Use division to convert the milliseconds to the metric you are solving for, and then use the remainder operator to capture the remainder of the specific unit you are targeting.<\/p>\n<p><code>toLocaleString<\/code> is a convenient little method that allows us to ensure our values are represented with a minimum of two digits by prepending a &#8216;0&#8217; when the value is a single digit. This way, five seconds appears as &#8220;05&#8221; instead of &#8220;5&#8221;:<\/p>\n<pre><code class=\"language-ts\">.toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n<\/code><\/pre>\n<h2>Create Animation Loop<\/h2>\n<p>We now have a function that calculates the remaining time and converts it to days, hours, minutes, and seconds. Next, we need to create a loop that will continuously run this function. 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 we want to execute 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. In our situation, we can create an animation loop by calling <code>requestAnimationFrame()<\/code> at the end of our <code>tick()<\/code> function and pass the <code>tick()<\/code> function as a callback.<\/p>\n<pre><code class=\"language-ts\">requestAnimationFrame(this.tick.bind(this));\n<\/code><\/pre>\n<p>To start our animation loop, we need to call the <code>tick()<\/code> function just once when the component connects to the DOM. To do that, we can use the lifecycle method <code>componentWillLoad()<\/code>:<\/p>\n<pre><code class=\"language-ts\">componentWillLoad() {\n  this.endDateObj = new Date(this.endDate);\n  this.tick();\n}\n<\/code><\/pre>\n<h2><em>Time<\/em> to Render<\/h2>\n<p>With all our necessary values calculated and updating, we can now render them on the screen.<\/p>\n<pre><code class=\"language-jsx\">render() {\n  return (\n    &lt;Host&gt;\n      &lt;div class=&quot;column&quot;&gt;\n        &lt;p class=&quot;label&quot;&gt;Days&lt;\/p&gt;\n        &lt;p class=&quot;value&quot;&gt;{this.days}&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;p class=&quot;colon&quot;&gt;:&lt;\/p&gt;\n      &lt;div class=&quot;column&quot;&gt;\n        &lt;p class=&quot;label&quot;&gt;Hours&lt;\/p&gt;\n        &lt;p class=&quot;value&quot;&gt;{this.hours}&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;p class=&quot;colon&quot;&gt;:&lt;\/p&gt;\n      &lt;div class=&quot;column&quot;&gt;\n        &lt;p class=&quot;label&quot;&gt;Minutes&lt;\/p&gt;\n        &lt;p class=&quot;value&quot;&gt;{this.minutes}&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;p class=&quot;colon&quot;&gt;:&lt;\/p&gt;\n      &lt;div class=&quot;column&quot;&gt;\n        &lt;p class=&quot;label&quot;&gt;Seconds&lt;\/p&gt;\n        &lt;p class=&quot;value&quot;&gt;{this.seconds}&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/Host&gt;\n  );\n}\n<\/code><\/pre>\n<p>To see our countdown tracker in action, we can use it in our <code>index.html<\/code> file and specify the <code>end-date<\/code> in ISO format.<\/p>\n<pre><code class=\"language-html\">&lt;body&gt;\n  &lt;countdown-tracker end-date=&quot;2021-09-28&quot; \/&gt;\n&lt;\/body&gt;\n<\/code><\/pre>\n<p>You can set the <code>end-date<\/code> to whatever date and time you like as long as it is in <a href=\"https:\/\/www.w3.org\/TR\/NOTE-datetime\">ISO format<\/a>.<\/p>\n<h2>Stopping the Animation Loop<\/h2>\n<p>We&#8217;re almost there, but you may have noticed that our countdown tracker starts to behave a little funny when the <code>endDate<\/code> finally arrives. Instead of stopping at 00:00:00:00, the tracker continues to count down into the negatives. This is because we don&#8217;t have any condition in our <code>tick()<\/code> function to check if the <code>endDate<\/code> has been reached. As a result, our animation loop never stops. To eventually stop the loop, we need to set a <code>stopId<\/code> for our <code>requestAnimationFrame()<\/code>. This is a number that is returned by <code>requestAnimationFrame()<\/code> to identify the animation request. When there is no more <code>timeRemaining<\/code>, we stop the loop by passing that <code>stopId<\/code> to <code>cancelAnimationFrame()<\/code> and exiting from the function.<\/p>\n<pre><code class=\"language-ts\">private stopId: number;\n\ntick() {\n  \/\/ example value: 80834343, time in milliseconds between endDate and now\n  const timeRemaining = this.endDateObj.getTime() - new Date().getTime();\n\n  if (timeRemaining &lt; 0) {\n    cancelAnimationFrame(this.stopId);\n    return;\n  }\n\n  this.seconds = Math.floor((timeRemaining \/ 1000) % 60)\n                 .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  this.minutes = Math.floor((timeRemaining \/ (1000 * 60)) % 60)\n                 .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  this.hours = Math.floor((timeRemaining \/ (1000 * 60 * 60)) % 24)\n               .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n  this.days = Math.floor((timeRemaining \/ (24 * 60 * 60 * 1000)) % 30)\n              .toLocaleString(&#039;en-US&#039;, { minimumIntegerDigits: 2 });\n\n  this.stopId = requestAnimationFrame(this.tick.bind(this));\n}\n<\/code><\/pre>\n<h2>Add Some Styles<\/h2>\n<p>Finally, let&#8217;s add some styles to make our countdown tracker more visually appealing. Feel free to be creative and incorporate your own styles here.<\/p>\n<pre><code class=\"language-css\">@import url(&#039;https:\/\/fonts.googleapis.com\/css2?family=Roboto+Mono:wght@400;700&amp;display=swap&#039;);\n\n:host {\n  font-family: &#039;Roboto Mono&#039;, monospace;\n  background-color: black;\n  color: white;\n  display: flex;\n  align-items: flex-end;\n  justify-content: space-around;\n  min-width: 415px;\n  max-width: 830px;\n}\n\n.column {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.label {\n  color: #d7dde2;\n  opacity: 0.8;\n  font-size: 18px;\n  font-weight: 700;\n  text-transform: uppercase;\n}\n\n.value,\n.colon {\n  font-size: 54px;\n}\n\np {\n  margin: 0;\n  padding: 0;\n}\n<\/code><\/pre>\n<p>With our styles in place, we now have a beautiful and fully functioning countdown tracker component that you can use in your own projects. A lot of the concepts discussed in this tutorial are also explained in this <a href=\"https:\/\/ionicframework.com\/blog\/building-with-stencil-audio-player-component\/\">Stencil audio player web component tutorial<\/a>. Feel free to check that out to learn more about building reusable components with <a href=\"https:\/\/stenciljs.com\/\">Stencil<\/a>. As you continue to build more components, you can use them to create an entire design system that can be used across different frameworks.<\/p>\n<p>View the countdown tracker component in action on the <a href=\"https:\/\/ionic.io\/events\">Ionic events site<\/a>, and while you\u2019re there, sign up for the Ionic Event on September 28th. Lots of exciting Ionic product updates will be announced, including the latest Stencil news. Happy coding! \ud83d\ude00<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we are going to build a countdown tracker component using Stencil. Countdown trackers are a great way to both inform your users of an event, as well as generate excitement around the event. By the end of this tutorial you\u2019ll have a countdown tracker component that you can reuse and customize for [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":3840,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"1","publish_post_category":"21","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"533286","discourse_permalink":"https:\/\/forum.ionicframework.com\/t\/building-with-stencil-countdown-tracker\/215341","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,223,124],"tags":[140,76,82],"class_list":["post-3839","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-all","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: Countdown Tracker - 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-countdown-tracker\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building with Stencil: Countdown Tracker\" \/>\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-countdown-tracker\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-22T21:08:09+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-21T05:32:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-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-countdown-tracker#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker\"},\"author\":{\"name\":\"Anthony Giuliano\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/a3190e4d49187220d0c720f2ceab9b58\"},\"headline\":\"Building with Stencil: Countdown Tracker\",\"datePublished\":\"2021-09-22T21:08:09+00:00\",\"dateModified\":\"2023-01-21T05:32:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker\"},\"wordCount\":1176,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png\",\"keywords\":[\"Design Systems\",\"stencil\",\"web components\"],\"articleSection\":[\"All\",\"Stencil\",\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker\",\"url\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker\",\"name\":\"Building with Stencil: Countdown Tracker - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png\",\"datePublished\":\"2021-09-22T21:08:09+00:00\",\"dateModified\":\"2023-01-21T05:32:59+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-countdown-tracker#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png\",\"width\":1600,\"height\":880},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building with Stencil: Countdown Tracker\"}]},{\"@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: Countdown Tracker - 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-countdown-tracker","og_locale":"en_US","og_type":"article","og_title":"Building with Stencil: Countdown Tracker","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-countdown-tracker","og_site_name":"Ionic Blog","article_published_time":"2021-09-22T21:08:09+00:00","article_modified_time":"2023-01-21T05:32:59+00:00","og_image":[{"width":1600,"height":880,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-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-countdown-tracker#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker"},"author":{"name":"Anthony Giuliano","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/a3190e4d49187220d0c720f2ceab9b58"},"headline":"Building with Stencil: Countdown Tracker","datePublished":"2021-09-22T21:08:09+00:00","dateModified":"2023-01-21T05:32:59+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker"},"wordCount":1176,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png","keywords":["Design Systems","stencil","web components"],"articleSection":["All","Stencil","Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker","url":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker","name":"Building with Stencil: Countdown Tracker - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png","datePublished":"2021-09-22T21:08:09+00:00","dateModified":"2023-01-21T05:32:59+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-countdown-tracker#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/09\/stencil-ticker-feature-image.png","width":1600,"height":880},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-countdown-tracker#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Building with Stencil: Countdown Tracker"}]},{"@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-ticker-feature-image.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3839","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=3839"}],"version-history":[{"count":1,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3839\/revisions"}],"predecessor-version":[{"id":4716,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3839\/revisions\/4716"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/3840"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=3839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=3839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=3839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}