{"id":3766,"date":"2021-07-19T17:04:14","date_gmt":"2021-07-19T17:04:14","guid":{"rendered":"https:\/\/ionicframework.com\/blog\/?p=3766"},"modified":"2023-01-21T00:33:26","modified_gmt":"2023-01-21T05:33:26","slug":"building-with-stencil-calendar-component","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component","title":{"rendered":"Building with Stencil: Calendar Component"},"content":{"rendered":"<p>Take a look at the month view of a calendar and you will see several rows of numbers. The numbers themselves, increasing in value one after the other, are arranged in columns. HTML and CSS provide us with a number of tools to display content in rows and columns. Making a calendar component should be easy, right? Right?<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/calendar-edge.png\" alt=\"You checked for edge cases right?\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" style=\"--smush-placeholder-width: 2500px; --smush-placeholder-aspect-ratio: 2500\/2500;\"><noscript><img decoding=\"async\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/calendar-edge.png\" alt=\"You checked for edge cases right?\"><\/noscript><\/p>\n<p>When we look at the first calendar day in a month, it could fall on any day of the week. This in turn can push the last day of the month to also fall on any day of the week. That variation can mean that there are six weeks (six rows) in some months, but only five weeks (rows) in others. Then of course there are the number of days in the month and oddities such as leap years.<\/p>\n<p>When we turn to <a href=\"https:\/\/stenciljs.com\/\" rel=\"noopener\" target=\"_blank\">Stencil<\/a> (and Web Components in general), all of these variations beg the question &#8220;What goes in my template if I do not know what I will need to display?&#8221; The answer is to figure out what you will need to display before you display it. We can leverage the Stencil component lifecycle to override <code>componentWillRender()<\/code> and perform the required calculations.<\/p>\n<p><!--more--><\/p>\n<h2>Building with Stencil: It is About Time!<\/h2>\n<p>If you think about any single given day on the calendar, you are really taking in several pieces of information at once. First is the integer representing the day of the month &#8211; and it is usually plastered in a giant font somewhere in each grid square. The second is that by the time you land on a day of the month, you likely already know the month and year. Finally, as your eyes rest upon a grid square, you are mentally selecting it, and know whether that selection represents today or not.<\/p>\n<blockquote><p>\n  These implied and inferred pieces of information fall in no particular order, and any correlation is completely made up by me for the purposes of the flow of this blog post. \ud83e\udd2a<\/p><\/blockquote>\n<p>These are all important pieces of data we will need when rendering out each day in the calendar, so I like to have a class that represents them which I call <code>Day<\/code>. You might think &#8220;Why not just use the JavaScript <code>Date<\/code> class? The reason for this decision has to do with the <code>selected<\/code> and <code>today<\/code> properties that are <code>boolean<\/code> values used in helping render the appropriate styles on the calendar grid.<\/p>\n<pre><code class=\"language-ts\">export default class Day {\n  date: number = null;\n  month: number = null;\n  year: number = null;\n\n  selected: boolean = false;\n  today: boolean = false;\n}\n<\/code><\/pre>\n<h2>What Day Is It?<\/h2>\n<p>From a component perspective, there are a few properties we will need to consider. The first is the desired date to display in the calendar versus the date being displayed in the calendar. The desired date might also be considered the &#8220;value&#8221; of the calendar and is exposed as a property (<code>@Prop()<\/code>). The date displayed in the calendar is a matter of how the user has interacted with the component to change its state (<code>@State()<\/code>). We will also need an <code>Array<\/code> of <code>Day<\/code> as a component-internal property to hold the days associated with the rendering of the displayed date.<\/p>\n<pre><code class=\"language-ts\">  @Prop( {mutable: true} ) value: Date = new Date();\n  @State() displayedDate: Date = new Date();\n  private days: Array&lt;Day&gt;;\n<\/code><\/pre>\n<p>For this calendar, when the user interacts with a day, that date will be set as the new <code>value<\/code>. Since <code>value<\/code> will be modified from inside the component, it will need to be marked as <code>mutable<\/code>. You may also want to emit an event that the <code>value<\/code> (selected date) has changed. Another consideration might be emitting an event for changes in the month being displayed.<\/p>\n<h2>Back to the Beginning<\/h2>\n<p>As we start implementing <code>componentWillRender()<\/code>, our first major task is to get back to the first day in the displayed month. The JavaScript <code>Date<\/code> constructor is perfectly suited for this by setting the third parameter, the day of the month, to one (1). The first day of the month does not mean you are at the first (upper-left) grid square, so we also need to go back in the calendar until we are on the first day of the week.<\/p>\n<pre><code class=\"language-ts\">componentWillRender() {\n  const today: Date = new Date();\n\n  \/\/ Calendar used in iteration\n  const calendar: Date = new Date(\n    this.displayedDate.getFullYear(),\n    this.displayedDate.getMonth(),\n    1\n  );\n\n  \/\/ First day of month may not be first day of week\n  \/\/ Roll back until first day of week\n  calendar.setDate( calendar.getDate() - calendar.getDay() );\n\n  \/\/ Clear days to be rendered  \n  this.days = []; \n\n  \/\/ ... more ...\n}\n<\/code><\/pre>\n<p>Perhaps not surprisingly, this now sets us up to iterate through the days of the month. Perhaps surprisingly, that is <strong>not<\/strong> what I like to do.<\/p>\n<h2>Building with Stencil One Day at a Time<\/h2>\n<p>My preferred approach for this iteration is to count to 42 (6 weeks possible x 7 days per week). If we make it through all 42 iterations, great. If we do not make it through all 42 iterations, we can break out of the loop at any time, and move on to the render. Additionally, it turns out that CSS Grid is perfectly suited for ending the iteration early, and will fill in the &#8220;gaps&#8221; for us.<\/p>\n<blockquote><p>\n  Though I have seen various takes on how to manage the iteration through the calendar, this &#8220;count to 42&#8221; approach leads to the most readable version that I have found. YMMV.<\/p><\/blockquote>\n<pre><code class=\"language-ts\">componentWillRender() {\n  const today: Date = new Date();\n\n  \/\/ Calendar used in iteration\n  const calendar: Date = new Date(\n    this.displayedDate.getFullYear(),\n    this.displayedDate.getMonth(),\n    1\n  );\n\n  \/\/ First day of month may not be first day of week\n  \/\/ Roll back until first day of week\n  calendar.setDate( calendar.getDate() - calendar.getDay() );\n\n  \/\/ Clear days to be rendered\n  this.days = [];\n\n  for( let d: number = 0; d &lt; 42; d++ ) {\n    \/\/ Day to be rendered\n    \/\/ Seed with current date in iteration\n    const day: Day = new Day();\n    day.year = calendar.getFullYear();\n    day.month = calendar.getMonth();\n\n    \/\/ Populate day in month\n    \/\/ Undefined date properties are not rendered\n    if(\n      calendar.getFullYear() === this.displayedDate.getFullYear() &amp;&amp;\n      calendar.getMonth() === this.displayedDate.getMonth()\n    ) day.date = calendar.getDate();\n\n    \/\/ Check for today\n    if(\n      calendar.getFullYear() === today.getFullYear() &amp;&amp;\n      calendar.getMonth() === today.getMonth() &amp;&amp;\n      calendar.getDate() === today.getDate()\n    ) day.today = true;\n\n    \/\/ Check for selection\n    if(\n      calendar.getFullYear() === this.value.getFullYear() &amp;&amp;\n      calendar.getMonth() === this.value.getMonth() &amp;&amp;\n      calendar.getDate() === this.value.getDate() &amp;&amp;\n      calendar.getMonth() === this.value.getMonth()\n    ) day.selected = true;\n\n    \/\/ Add to days to be rendered\n    this.days.push( day );\n\n    \/\/ Keep rolling\n    calendar.setDate( calendar.getDate() + 1 );\n\n    \/\/ Do not render the last week\n    \/\/ Depending on calendar layout\n    \/\/ Some months require five weeks\n    \/\/ Others six weeks (see May 2021)\n    if(\n      calendar.getDay() === 0 &amp;&amp;\n      calendar.getMonth() !== this.displayedDate.getMonth()\n    ) break;\n  }\n}  \n<\/code><\/pre>\n<p>Within each iteration, we seed the <code>Day<\/code> instance with the month and year, but not necessarily the day of the month. We can use this absence of data in the render. We also check to see if the date in the current iteration is today, or if it matches the <code>value<\/code> property. These flags will help us style the calendar appropriately. If we pass the end of the month being displayed, we are done and can return to the component lifecycle to actually render the calendar.<\/p>\n<h3>Once More, With Feeling<\/h3>\n<p>When it comes to the actual rendering of the calendar, I like to separate it semantically from the rest of the calendar. This helps keep the CSS more concise.<\/p>\n<p>The most interesting part of the CSS is the use of CSS Grid. The <code>grid-template-rows<\/code> property is specified as <code>repeat( auto-fill, 1fr )<\/code> which is what allows us to get away without having to complete the week at the end of the month, or outright leave a week off the end of the month if there are only five (5) weeks.<\/p>\n<pre><code class=\"language-css\">article {\n  box-sizing: border-box;\n  display: grid;\n  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;\n  grid-template-rows: repeat( auto-fill, 1fr );\n  gap: 0px 0px;\n  min-width: 100vw;\n  padding: 0 4px 4px 4px;  \n}\n\narticle button {\n  appearance: none;\n  -webkit-appearance: none;\n  background: none;\n  border: none;\n  box-sizing: border-box;\n  cursor: pointer;\n  font-family: -apple-system, sans-serif;    \n  font-size: 20px;  \n  margin: 3px;\n  min-height: calc( ( 100vw \/ 7 ) - 6px );\n  outline: none;\n  padding: 0;\n  -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 );                   \n  text-align: center;  \n}\n\narticle button[disabled] {\n  cursor: default;\n}\n\narticle button.selected {\n  background-color: rgba( 255, 0, 0, 0.10 );\n  border-radius: 100%;\n  color: #ff0000;\n  font-weight: 600;\n}\n\narticle button.today {\n  color: #ff0000;\n}\n\narticle button.selected.today {\n  background-color: #ff0000;\n  color: #ffffff;\n}\n<\/code><\/pre>\n<p>As you can probably tell from the CSS, each day in the month will be rendered as a <code>button<\/code> element. On that <code>button<\/code> element, we can use <code>data<\/code> attributes to store the day, month, and year that each represents. In the click handler, a reference to the <code>button<\/code> can be obtained using the <code>target<\/code> property of the <code>MouseEvent<\/code>. These values can then be parsed, and a <code>Date<\/code> object is then created to represent the date that was selected. This keeps us from having to store DOM references to each of the days being rendered. A <code>button<\/code> marked <code>disabled<\/code> will not fire the click handler.<\/p>\n<pre><code class=\"language-ts\">&lt;article&gt;\n  {this.days.map( ( day: Day ) =&gt;\n    &lt;button\n      class={{\n        selected: day.selected,\n        today: day.today\n      }}\n      data-date={day.date}\n      data-month={day.month}\n      data-year={day.year}\n      disabled={day.date === null ? true : false}\n      onClick={( evt: MouseEvent ) =&gt; this.doSelect( evt )}&gt;\n      {day.date}\n    &lt;\/button&gt;\n  ) }\n&lt;\/article&gt;\n<\/code><\/pre>\n<p>I call this whole technique of calculating what needs to be displayed before the actual rendering process &#8220;pre-rendering&#8221;. The approach is valuable not only in calendars but also in any situation where there can be a variable number of elements to be rendered. Dynamic SVG content is another place where this technique comes in handy.<\/p>\n<p><img decoding=\"async\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/hoyt-calendar.png\" alt=\"An Image of the calendar component\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" class=\"lazyload\" style=\"--smush-placeholder-width: 3471px; --smush-placeholder-aspect-ratio: 3471\/2818;\"><noscript><img decoding=\"async\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/hoyt-calendar.png\" alt=\"An Image of the calendar component\" class=\"\"><\/noscript><\/p>\n<blockquote><p>\n  Modern calendar designs do not show the dates for the days outside of the month being rendered. This holds true for both Material Design and Apple Human Interface Guidelines. You can alter the pre-rendering to meet your requirements should they differ.<\/p><\/blockquote>\n<p>Could you forego the pre-rendering, and do all the calculations in the render proper? With enough braces, brackets, and parenthesis, you probably could. This approach however gives us a clean separation between the data to be rendered and the render itself leading to readable and maintainable code.<\/p>\n<h2>Next Steps<\/h2>\n<p>A number of nuances to calendar rendering have not been addressed in this article. For example, Sunday is not always the first day of the week depending on your locale. More could also be done to address accessibility. And of course, changing the styles for different mobile operating systems would take considerable effort. Does this sound like a lot more work? Yes! <a href=\"https:\/\/ionicframework.com\/\" rel=\"noopener\" target=\"_blank\">Ionic Framework<\/a> can help. The announced Ionic Framework v6 includes modern calendars built to conform to the latest design guidelines, including accessibility.<\/p>\n<p>Check out the live <a href=\"http:\/\/temp.kevinhoyt.com\/ionic\/calendar\/\">demo<\/a> and get the complete <a href=\"https:\/\/github.com\/krhoyt\/Stencil-Examples\/tree\/main\/calendar\">code<\/a>.<\/p>\n<p>Come meet the Stencil team and hear what we&#8217;re working on for future releases! The Stencil Team is hosting Office Hours <a href=\"https:\/\/youtu.be\/aKXJp5d3LFM\">Wednesday, August 11th at 12pm CDT<\/a> and sharing their plans for the future. Can&#8217;t make the office hours in person? <a href=\"https:\/\/forms.gle\/dCsVYPQZ1GTe1neu5\">Ask your question ahead of time<\/a> and we&#8217;ll answer it live.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Take a look at the month view of a calendar and you will see several rows of numbers. The numbers themselves, increasing in value one after the other, are arranged in columns. HTML and CSS provide us with a number of tools to display content in rows and columns. Making a calendar component should be [&hellip;]<\/p>\n","protected":false},"author":85,"featured_media":3767,"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":"511167","discourse_permalink":"https:\/\/forum.ionicframework.com\/t\/building-with-stencil-calendar-component\/212691","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,121,223],"tags":[140,76,82],"class_list":["post-3766","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-all","category-engineering","category-stencil","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: Calendar Component - Ionic Blog<\/title>\n<meta name=\"description\" content=\"Learn how to create a calendar component with Stencil in this Building with Stencil blog series. Check out our other docs to get started.\" \/>\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-calendar-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: Calendar Component\" \/>\n<meta property=\"og:description\" content=\"Learn how to create a calendar component with Stencil in this Building with Stencil blog series. Check out our other docs to get started.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-07-19T17:04:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-21T05:33:26+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png\" \/>\n\t<meta property=\"og:image:width\" content=\"4000\" \/>\n\t<meta property=\"og:image:height\" content=\"2250\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Kevin Hoyt\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kevin Hoyt\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 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-calendar-component#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component\"},\"author\":{\"name\":\"Kevin Hoyt\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/5cf8e478fa22da64450a7292b5596c81\"},\"headline\":\"Building with Stencil: Calendar Component\",\"datePublished\":\"2021-07-19T17:04:14+00:00\",\"dateModified\":\"2023-01-21T05:33:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component\"},\"wordCount\":1341,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png\",\"keywords\":[\"Design Systems\",\"stencil\",\"web components\"],\"articleSection\":[\"All\",\"Engineering\",\"Stencil\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component\",\"url\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component\",\"name\":\"Building with Stencil: Calendar Component - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png\",\"datePublished\":\"2021-07-19T17:04:14+00:00\",\"dateModified\":\"2023-01-21T05:33:26+00:00\",\"description\":\"Learn how to create a calendar component with Stencil in this Building with Stencil blog series. Check out our other docs to get started.\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png\",\"width\":4000,\"height\":2250,\"caption\":\"Building with Stencil: Calendar\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building with Stencil: Calendar 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\/5cf8e478fa22da64450a7292b5596c81\",\"name\":\"Kevin Hoyt\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/2520666-150x150.jpg\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/2520666-150x150.jpg\",\"caption\":\"Kevin Hoyt\"},\"url\":\"https:\/\/ionic.io\/blog\/author\/hoyt\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building with Stencil: Calendar Component - Ionic Blog","description":"Learn how to create a calendar component with Stencil in this Building with Stencil blog series. Check out our other docs to get started.","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-calendar-component","og_locale":"en_US","og_type":"article","og_title":"Building with Stencil: Calendar Component","og_description":"Learn how to create a calendar component with Stencil in this Building with Stencil blog series. Check out our other docs to get started.","og_url":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component","og_site_name":"Ionic Blog","article_published_time":"2021-07-19T17:04:14+00:00","article_modified_time":"2023-01-21T05:33:26+00:00","og_image":[{"width":4000,"height":2250,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png","type":"image\/png"}],"author":"Kevin Hoyt","twitter_card":"summary_large_image","twitter_creator":"@ionicframework","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Kevin Hoyt","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component"},"author":{"name":"Kevin Hoyt","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/5cf8e478fa22da64450a7292b5596c81"},"headline":"Building with Stencil: Calendar Component","datePublished":"2021-07-19T17:04:14+00:00","dateModified":"2023-01-21T05:33:26+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component"},"wordCount":1341,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png","keywords":["Design Systems","stencil","web components"],"articleSection":["All","Engineering","Stencil"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component","url":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component","name":"Building with Stencil: Calendar Component - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png","datePublished":"2021-07-19T17:04:14+00:00","dateModified":"2023-01-21T05:33:26+00:00","description":"Learn how to create a calendar component with Stencil in this Building with Stencil blog series. Check out our other docs to get started.","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png","width":4000,"height":2250,"caption":"Building with Stencil: Calendar"},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/building-with-stencil-calendar-component#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Building with Stencil: Calendar 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\/5cf8e478fa22da64450a7292b5596c81","name":"Kevin Hoyt","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/2520666-150x150.jpg","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/2520666-150x150.jpg","caption":"Kevin Hoyt"},"url":"https:\/\/ionic.io\/blog\/author\/hoyt"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2021\/07\/ionic-blog-post-image_first-look-01.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3766","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\/85"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=3766"}],"version-history":[{"count":1,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3766\/revisions"}],"predecessor-version":[{"id":4719,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/3766\/revisions\/4719"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/3767"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=3766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=3766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=3766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}