<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pedro Lopes</title>
    <description>The latest articles on DEV Community by Pedro Lopes (@pedro_lopes_3afabcd341c8f).</description>
    <link>https://dev.to/pedro_lopes_3afabcd341c8f</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3832796%2Fef6074df-1d54-4fd8-b2ce-d6d5c20fe389.png</url>
      <title>DEV Community: Pedro Lopes</title>
      <link>https://dev.to/pedro_lopes_3afabcd341c8f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pedro_lopes_3afabcd341c8f"/>
    <language>en</language>
    <item>
      <title>FullCalendar is 500Kb. I built an alternative at 78Kb — with React, Vue &amp; Angular support</title>
      <dc:creator>Pedro Lopes</dc:creator>
      <pubDate>Fri, 20 Mar 2026 11:50:51 +0000</pubDate>
      <link>https://dev.to/pedro_lopes_3afabcd341c8f/fullcalendar-is-500kb-i-built-an-alternative-at-78kb-with-react-vue-angular-support-4a85</link>
      <guid>https://dev.to/pedro_lopes_3afabcd341c8f/fullcalendar-is-500kb-i-built-an-alternative-at-78kb-with-react-vue-angular-support-4a85</guid>
      <description>&lt;p&gt;If you've ever needed a calendar component in a web app, you've probably landed on FullCalendar. It's the industry default — and for good reason. It's feature-rich and battle-tested.&lt;/p&gt;

&lt;p&gt;But here's what the docs don't tell you up front: the full bundle is &lt;strong&gt;over 500KB&lt;/strong&gt;. It pulls in its own date library. The API surface is enormous. And if you just need a clean calendar with drag &amp;amp; drop, event fetching, and maybe a date picker — you're carrying a lot of weight you'll never use.&lt;/p&gt;

&lt;p&gt;I noticed this problem while building a scheduling feature. I needed month/week/day views, async event loading from an API, drag &amp;amp; drop, and React compatibility. FullCalendar could do it, but it felt like using a freight elevator to go up one floor.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;&lt;a href="https://www.simplecalendarjs.com/" rel="noopener noreferrer"&gt;SimpleCalendarJS&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
   &lt;img src="https://camo.githubusercontent.com/fc50417f63e1db1cd9e7a7dd0341b61384b35c2f7f783ac839f7680c37153b97/68747470733a2f2f7777772e73696d706c6563616c656e6461726a732e636f6d2f53637265656e73686f74732f53637265656e73686f7430312d4d6f6e7468566965772e706e67" alt="SimpleCalendarJS Month View" width="1271" height="609"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;4 view modes&lt;/strong&gt; — Month, Week, Day, and List&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drag &amp;amp; drop&lt;/strong&gt; event moving and resizing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date &amp;amp; range picker&lt;/strong&gt; modes built-in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async event fetching&lt;/strong&gt; with &lt;code&gt;fetchEvents: async (start, end) =&amp;gt; { ... }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Official wrappers&lt;/strong&gt; for React, Vue 3, and Angular&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;34+ locales&lt;/strong&gt; via the native &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; API (no extra bundles)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RTL language support&lt;/strong&gt; (Arabic, Hebrew, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark mode&lt;/strong&gt; via CSS custom properties&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero dependencies&lt;/strong&gt; — pure vanilla JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the entire thing is &lt;strong&gt;78KB minified&lt;/strong&gt;. The full package including framework wrappers is 76KB.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting started is genuinely simple
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;simple-calendar-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-calendar-js/dist/simple-calendar-js.min.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;calendar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SimpleCalendarJs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#calendar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;defaultView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;month&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fetchEvents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;onEventClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Event clicked:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SimpleCalendar&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple-calendar-js/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SimpleCalendar&lt;/span&gt;
      &lt;span class="na"&gt;defaultView&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"month"&lt;/span&gt;
      &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en-US"&lt;/span&gt;
      &lt;span class="na"&gt;fetchEvents&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;img src="https://camo.githubusercontent.com/84192c740e8db377c1624d3a05f2e0ea776901d12ce10c4ba6b03f47fbda9e38/68747470733a2f2f7777772e73696d706c6563616c656e6461726a732e636f6d2f53637265656e73686f74732f53637265656e73686f7430322d5765656b566965772e706e67" alt="SimpleCalendarJS Week View" width="1271" height="609"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The honest comparison
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend SimpleCalendarJS does everything FullCalendar does — it doesn't. FullCalendar has more niche configuration options and a longer history of edge-case fixes.&lt;/p&gt;

&lt;p&gt;But for the &lt;strong&gt;vast majority of real-world use cases&lt;/strong&gt; — a scheduling UI, a booking widget, an event display, a date picker — SimpleCalendarJS covers the ground at a fraction of the size.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SimpleCalendarJS&lt;/th&gt;
&lt;th&gt;FullCalendar&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bundle size&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;78KB&lt;/strong&gt; (min)&lt;/td&gt;
&lt;td&gt;~500KB+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Zero&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires own date lib&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React / Vue / Angular&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (separate packages)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drag &amp;amp; Drop&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (plugin required)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Date / Range Picker&lt;/td&gt;
&lt;td&gt;✅ built-in&lt;/td&gt;
&lt;td&gt;❌ (separate)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTL Support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Async events&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dark mode&lt;/td&gt;
&lt;td&gt;✅ CSS vars&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free for open source&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Why bundle size matters more than you think
&lt;/h2&gt;

&lt;p&gt;When you're server-side rendering a Next.js app or loading a React SPA on a mobile connection, 500KB vs 78KB is the difference between a 3-second interaction and an instant one. Calendar components often sit on high-traffic booking pages or dashboards. That weight compounds.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; API is already in every modern browser — there's no reason a calendar library needs to ship its own locale data. SimpleCalendarJS leans on what the platform gives you for free.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm actively working on the library and there's a public roadmap. If you hit a use case it doesn't cover, open an issue — that's genuinely how the feature list grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;strong&gt;Website &amp;amp; live sandbox:&lt;/strong&gt; &lt;a href="https://www.simplecalendarjs.com/" rel="noopener noreferrer"&gt;simplecalendarjs.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/simple-calendar-js" rel="noopener noreferrer"&gt;simple-calendar-js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;⭐ &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/pclslopes/SimpleCalendarJs" rel="noopener noreferrer"&gt;pclslopes/SimpleCalendarJs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it saves you time, a GitHub star helps more developers find it — small projects live and die by discoverability. 🙏&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>performance</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
