<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Idris Abdul-Lateef - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Idris Abdul-Lateef - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 12 May 2026 20:31:04 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/eedris/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Add Custom Buttons to a Date Picker in Flatpickr ]]>
                </title>
                <description>
                    <![CDATA[ If you've ever had to use a date picker in a web frontend project, chances are that you've used flatpickr.  For the unacquainted, flatpickr is one of the most popular date picker libraries in the open source-verse. It's framework-agnostic, highly cus... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-custom-buttons-to-flatpickr/</link>
                <guid isPermaLink="false">66ba2c9bab41bfc0b9b131da</guid>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ User Interface ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Abdul-Lateef ]]>
                </dc:creator>
                <pubDate>Wed, 17 Jan 2024 16:34:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/b01117c062c14a0d7f54f256baf09808482b6505_2_1024x512.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've ever had to use a date picker in a web frontend project, chances are that you've used flatpickr. </p>
<p>For the unacquainted, <a target="_blank" href="https://flatpickr.js.org/">flatpickr</a> is one of the most popular date picker libraries in the open source-verse. It's framework-agnostic, highly customizable, and lightweight.</p>
<p>I recently had to use it in a Next.js codebase and there was a peculiar use case I had. The built-in behavior is that dates are applied immediately when selected, and thereafter the date picker disappears. </p>
<p>What I really wanted, however, was to be able to pick dates and not have the modal disappear the moment I did so. I wanted to be able to keep picking dates and only have it applied when I clicked on an "Apply" button. I also wanted a "Clear" button to clear applied dates.</p>
<p>Ordinarily, flatpickr's API has methods you can work with to get these functionalities, but you won't get buttons on the date picker itself. </p>
<p>Even while there is a <a target="_blank" href="https://flatpickr.js.org/plugins/#confirmdate">plugin</a> that adds a button to the date picker to manually apply dates, it doesn't work for date ranges (which was what I needed it for) and the button's look didn't really blend with the overall theme of the app I was building. </p>
<p>I had no other option but to come up with my own solution. But how do you get your own buttons to appear on flatpickr's date picker?</p>
<h2 id="heading-how-to-set-up-flatpickr">How to Set Up flatpickr</h2>
<p>First things first, install the package:</p>
<pre><code class="lang-bash">npm install flatpickr
</code></pre>
<p>Next, you need a <code>DatePicker</code> component that will encapsulate the custom date picker and make it reusable. This component should have an <code>onChange</code> prop which will be passed a callback that will be called whenever a date is applied:</p>
<pre><code class="lang-tsx">// DatePicker.tsx

const DatePicker: React.FC&lt;DatePickerProps&gt; = ({ onChange }) =&gt; {
  return &lt;div&gt;&lt;/div&gt;
}

export default DatePicker

interface DatePickerProps {
  onChange: (date: Date[]) =&gt; void
}
</code></pre>
<p>Next, you'll need to set up flatpickr itself. You're going to bring in some exports from the flatpickr package. In the markup, you'll add a text input element, which will be the date picker input, and pass it an element ref variable that'll be used to instantiate the flatpickr instance with a couple of configuration options:</p>
<pre><code class="lang-tsx">// DatePicker.tsx

import { ElementRef, useEffect, useRef, useState } from "react"
import flatpickr from "flatpickr"

import { Instance as Flatpickr } from "flatpickr/dist/types/instance"
import "flatpickr/dist/flatpickr.min.css"

const DatePicker: React.FC&lt;DatePickerProps&gt; = ({ onChange }) =&gt; {
  const [flatpickrInstance, setFlatpickrInstance] = useState&lt;Flatpickr&gt;()
  const datePickerRef = useRef&lt;ElementRef&lt;"input"&gt;&gt;(null)

  useEffect(() =&gt; {
    if (datePickerRef.current) {
      const flatpickrInstance = flatpickr(datePickerRef.current, {
        static: true,
        closeOnSelect: false,
      })

      setFlatpickrInstance(flatpickrInstance)
    }

    return () =&gt; flatpickrInstance?.destroy()
  }, [])

  return (
    &lt;div&gt;
      &lt;input ref={datePickerRef} type="text" placeholder="Select date..." /&gt;
    &lt;/div&gt;
  )
}
...
</code></pre>
<p>For the configuration options, <code>static</code> is set to true so the date picker modal is anchored to the date picker input and <code>closeOnSelect</code> is false so the date picker modal doesn't disappear when a date is selected. </p>
<p>This is how the date picker looks so far:
<img src="https://www.freecodecamp.org/news/content/images/2024/01/Screenshot-2024-01-14-153953.png" alt="Screenshot-2024-01-14-153953" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-the-buttons">How to Add the Buttons</h2>
<p>We've arrive at the main attraction of the day. From the snippet below, you'll notice two new imports: <code>createPortal</code> from react-dom and a pre-styled <code>Button</code> component. <code>createPortal</code> is going to play a very special role as you'll see.</p>
<pre><code class="lang-tsx">// DatePicker.tsx

import { ElementRef, useEffect, useRef, useState } from "react"
import { createPortal } from "react-dom"
import flatpickr from "flatpickr"
import Button from "./Button"

import { Instance as Flatpickr } from "flatpickr/dist/types/instance"
import "flatpickr/dist/flatpickr.min.css"

...
</code></pre>
<p>Moving on to the body of the <code>DatePicker</code> component, you'll notice some changes too. </p>
<p>There's <code>dates</code> which will store selected date(s) (or an empty array if no date is selected) and <code>applyDate</code> which will hold the callback to call when the 'Apply' button is clicked. </p>
<p>In the configuration object, you'll find two flatpickr hooks: <code>onChange</code> that gets triggered whenever a date is picked and receives an array of the currently selected dates, and <code>onClose</code> that gets triggered when the date picker modal is closed. </p>
<p>Within the body of these hooks are implementations that specify the date picker's behavior.</p>
<pre><code class="lang-tsx">// DatePicker.tsx

...
const DatePicker: React.FC&lt;DatePickerProps&gt; = ({ onChange }) =&gt; {
  const [flatpickrInstance, setFlatpickrInstance] = useState&lt;Flatpickr&gt;()
  const datePickerRef = useRef&lt;ElementRef&lt;"input"&gt;&gt;(null)
  const dates = useRef&lt;Date[]&gt;([])
  const [applyDate, setApplyDate] = useState(() =&gt; () =&gt; {})

  useEffect(() =&gt; {
    if (datePickerRef.current) {
      const flatpickrInstance = flatpickr(datePickerRef.current, {
        static: true,
        closeOnSelect: false,
        onChange: (selectedDates) =&gt; {
          if (selectedDates.length === 0) {
            onChange([])
            dates.current = []
          }

          setApplyDate(() =&gt; {
            return () =&gt; {
              dates.current = selectedDates
              onChange(selectedDates)
              flatpickrInstance.close()
            }
          })
        },
        onClose: () =&gt; {
          flatpickrInstance.setDate(dates.current)
        },
      })

      setFlatpickrInstance(flatpickrInstance)
    }

    return () =&gt; flatpickrInstance?.destroy()
  }, [])


  return (
    &lt;div&gt;  
...
</code></pre>
<p>We've gotten to the part where you finally put the custom buttons inside the date picker. This is where <code>createPortal</code> comes to shine. </p>
<p>The <code>flatpickrInstance</code> has a property, <code>calendarContainer</code>, which holds a reference to the date picker's containing <code>div</code> element. This is where you'll project the custom buttons, just beneath the calendar part of the date picker, using <a target="_blank" href="https://react.dev/reference/react-dom/createPortal">react portal</a>.</p>
<pre><code class="lang-tsx">// DatePicker.tsx

...
  return (
    &lt;div&gt;
      &lt;input ref={datePickerRef} type="text" placeholder="Select date..." /&gt;
      {flatpickrInstance &amp;&amp;
        createPortal(
          &lt;div className="flex justify-center gap-3 py-2"&gt;
            &lt;Button
              text="Clear"
              bgColor="#F8F8F8"
              textColor="#292A2E"
              onClick={() =&gt; {
                flatpickrInstance.clear(true)
                flatpickrInstance.close()
              }}
            /&gt;
            &lt;Button
              text="Apply"
              bgColor="#569ff7"
              textColor="#FFF"
              onClick={applyDate}
            /&gt;
          &lt;/div&gt;,
          flatpickrInstance.calendarContainer
        )}
    &lt;/div&gt;
  )
}

export default DatePicker
...
</code></pre>
<p>Put together, this is the final code output:</p>
<pre><code class="lang-tsx">// DatePicker.tsx

import { ElementRef, useEffect, useRef, useState } from "react"
import { createPortal } from "react-dom"
import flatpickr from "flatpickr"
import Button from "./Button"

import { Instance as Flatpickr } from "flatpickr/dist/types/instance"
import "flatpickr/dist/flatpickr.min.css"

const DatePicker: React.FC&lt;DatePickerProps&gt; = ({ onChange }) =&gt; {
  const [flatpickrInstance, setFlatpickrInstance] = useState&lt;Flatpickr&gt;()
  const datePickerRef = useRef&lt;ElementRef&lt;"input"&gt;&gt;(null)
  const dates = useRef&lt;Date[]&gt;([])
  const [applyDate, setApplyDate] = useState(() =&gt; () =&gt; {})

  useEffect(() =&gt; {
    if (datePickerRef.current) {
      const flatpickrInstance = flatpickr(datePickerRef.current, {
        static: true,
        closeOnSelect: false,
        onChange: (selectedDates) =&gt; {
          if (selectedDates.length === 0) {
            onChange([])
            dates.current = []
          }

          setApplyDate(() =&gt; {
            return () =&gt; {
              dates.current = selectedDates
              onChange(selectedDates)
              flatpickrInstance.close()
            }
          })
        },
        onClose: () =&gt; {
          flatpickrInstance.setDate(dates.current)
        },
      })

      setFlatpickrInstance(flatpickrInstance)
    }

    return () =&gt; flatpickrInstance?.destroy()
  }, [])

  return (
    &lt;div&gt;
      &lt;input ref={datePickerRef} type="text" placeholder="Select date..." /&gt;
      {flatpickrInstance &amp;&amp;
        createPortal(
          &lt;div className="flex justify-center gap-3 py-2"&gt;
            &lt;Button
              text="Clear"
              bgColor="#F8F8F8"
              textColor="#292A2E"
              onClick={() =&gt; {
                flatpickrInstance.clear(true)
                flatpickrInstance.close()
              }}
            /&gt;
            &lt;Button
              text="Apply"
              bgColor="#569ff7"
              textColor="#FFF"
              onClick={applyDate}
            /&gt;
          &lt;/div&gt;,
          flatpickrInstance.calendarContainer
        )}
    &lt;/div&gt;
  )
}

export default DatePicker

interface DatePickerProps {
  onChange: (date: Date[]) =&gt; void
}
</code></pre>
<p>And this is how the date picker now looks with the custom buttons:
<img src="https://www.freecodecamp.org/news/content/images/2024/01/Screenshot-2024-01-16-085906.png" alt="Screenshot-2024-01-16-085906" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The date picker is now fully functional and can work for all <code>mode</code> options. There are tons of potential customizations you could possibly do using this technique. Hopefully, this article has done a good job of showing how flatpickr customization can be achieved.</p>
<h3 id="heading-enjoyed-this-article">❤️Enjoyed this article?</h3>
<p><strong>See more of my content!</strong> You can find more articles on my <a target="_blank" href="https://blog.eedris.dev">blog</a>.</p>
<p><strong>Want to connect?</strong> Link up with me on <a target="_blank" href="https://twitter.com/eedrxs">Twitter</a> or <a target="_blank" href="https://linkedin.com/in/eedris">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
