Repository: laboratoriobridge/bold
Pull request #544 (2020-02-10 16:49:35)

Some performance improvements, tests and the "name" property in DateRangeField


Patch:
diff --git a/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.tsx b/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.tsx
index 077802fa5..e427b9ac0 100644
--- a/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.tsx
+++ b/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.tsx
@@ -1,65 +1,38 @@
-import React, { useEffect, useRef, useState } from 'react'
+import React from 'react'
 
 import { CalendarProps } from '../..'
 
 import { RangeDateCalendar } from './RangeDateCalendar'
 
 export interface ControlledRangeDateCalendarProps extends CalendarProps {
-  values?: {
+  value?: {
     initialDate: Date
     finalDate: Date
   }
-  inputOnFocus?: number
+  inputOnFocus: number
   onChange?(initialDate: Date, finalDate: Date): void
 }
 
 export function ControlledRangeDateCalendar(props: ControlledRangeDateCalendarProps) {
-  const { inputOnFocus, onChange, values, onDayClick, ...rest } = props
-  const [initialDate, setInitialDate] = useState<Date>(values ? values.initialDate : undefined)
-  const [finalDate, setFinalDate] = useState<Date>(values ? values.finalDate : undefined)
-  const cmpMounted = useRef(false)
-
-  // Call to onChange prop only after component has been mounted
-  useEffect(() => {
-    if (cmpMounted.current && onChange) {
-      onChange(initialDate, finalDate)
-      return
-    }
-    cmpMounted.current = true
-  }, [initialDate, finalDate])
-
-  useEffect(() => {
-    if (values) {
-      if (initialDate && finalDate && initialDate > finalDate) {
-        setInitialDate(values.finalDate)
-        setFinalDate(values.initialDate)
-      } else {
-        setInitialDate(values.initialDate)
-        setFinalDate(values.finalDate)
-      }
-    }
-  }, [values])
+  const { inputOnFocus, onChange, value, onDayClick, ...rest } = props
 
   const controllDayClick = (day: Date) => {
     onDayClick && onDayClick(day)
     if (inputOnFocus === 1) {
-      if (day < initialDate) {
-        setInitialDate(day)
-        setFinalDate(finalDate)
-      } else if (day > finalDate) {
-        setInitialDate(day)
-        setFinalDate(undefined)
+      if (day < value?.initialDate) {
+        onChange(day, value?.finalDate)
+      } else if (day > value?.finalDate) {
+        onChange(day, undefined)
       } else {
-        setInitialDate(day)
+        onChange(day, value?.finalDate)
       }
       return
     }
     if (inputOnFocus === 2) {
-      if (finalDate && day < initialDate) {
-        setInitialDate(day)
-        setFinalDate(undefined)
+      if (value?.finalDate && day < value?.initialDate) {
+        onChange(day, undefined)
       } else {
-        setFinalDate(day)
+        onChange(value?.initialDate, day)
       }
       return
     }
@@ -68,10 +41,15 @@ export function ControlledRangeDateCalendar(props: ControlledRangeDateCalendarPr
   return (
     <RangeDateCalendar
       {...rest}
-      initialDate={initialDate}
-      finalDate={finalDate}
+      initialDate={value?.initialDate}
+      finalDate={value?.finalDate}
       onDayClick={controllDayClick}
       inputOnFocus={inputOnFocus}
     />
   )
 }
+
+ControlledRangeDateCalendar.defaultProps = {
+  onChange: () => null,
+  onDayClick: () => null,
+} as Partial<ControlledRangeDateCalendarProps>
diff --git a/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.tsx b/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.tsx
index cdf3fe763..756b91d71 100644
--- a/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.tsx
+++ b/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.tsx
@@ -8,7 +8,7 @@ import { GenericRangeCalendar } from '../GenericRangeCalendar/GenericRangeCalend
 export interface RangeDateCalendarProps extends CalendarProps {
   initialDate: Date
   finalDate: Date
-  inputOnFocus?: number
+  inputOnFocus: number
 }
 
 export function RangeDateCalendar({ initialDate, finalDate, inputOnFocus, ...rest }: RangeDateCalendarProps) {
diff --git a/src/components/RangeDateField/BaseRangeDateInput.tsx b/src/components/RangeDateField/BaseRangeDateInput.tsx
index 72cea2364..783bdf3c9 100644
--- a/src/components/RangeDateField/BaseRangeDateInput.tsx
+++ b/src/components/RangeDateField/BaseRangeDateInput.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import { CSSProperties, Ref, useEffect, useRef, useState } from 'react'
+import { CSSProperties, Ref, useRef } from 'react'
 
 import { useLocale } from '../../i18n'
 import { ExternalStyles, focusBoxShadow, Theme, useStyles } from '../../styles'
@@ -19,6 +19,11 @@ export interface BaseRangeDateInputProps {
    */
   value?: Period
 
+  /**
+   * Component name
+   */
+  name?: string
+
   /**
    * "minDate" defines the minimum allowed date
    */
@@ -101,33 +106,28 @@ export interface BaseRangeDateInputProps {
 
 export function BaseRangeDateInput(props: BaseRangeDateInputProps) {
   const {
-    value,
     disabled,
-    onChange,
+    divRef,
     icon,
-    onIconClick,
     initialInputRef,
     finalInputRef,
-    onInputOnFocus,
-    minDate,
     maxDate,
-    divRef,
+    minDate,
+    name,
+    onChange,
+    onIconClick,
+    onInputOnFocus,
     rangeSeparator,
+    value,
     ...rest
   } = props
 
   const firstDateFieldRef = useRef<HTMLInputElement>()
   const secondDateFieldRef = useRef<HTMLInputElement>()
 
-  const [period, setPeriod] = useState(value)
   const { classes, css } = useStyles(createStyles, disabled)
   const className = css(classes.div, props.invalid && classes.invalid, props.style)
 
-  useEffect(() => {
-    onChange && onChange(value)
-    setPeriod(value ? value : ({ startDate: undefined, finalDate: undefined } as Period))
-  }, [value])
-
   const handleMinMaxDates = (date: Date) => {
     if (minDate && maxDate) {
       return date && date >= minDate && date <= maxDate ? date : undefined
@@ -143,10 +143,14 @@ export function BaseRangeDateInput(props: BaseRangeDateInputProps) {
 
   const onChangeStart = (date: Date) => {
     const startDate = handleMinMaxDates(date)
-    const finalDate = startDate && startDate > period.finalDate ? undefined : period.finalDate
-    const aux = { startDate, finalDate } as Period
+    const finalDate =
+      value?.startDate && value?.finalDate && startDate && startDate > value?.finalDate ? undefined : value?.finalDate
+    const aux = {
+      startDate,
+      finalDate,
+    } as Period
+
     onChange && onChange(aux)
-    setPeriod(aux)
     if (startDate) {
       secondDateFieldRef.current.focus()
     }
@@ -154,38 +158,37 @@ export function BaseRangeDateInput(props: BaseRangeDateInputProps) {
 
   const onChangeFinal = (date: Date) => {
     const auxFinalDate = handleMinMaxDates(date)
-    const startDate = auxFinalDate && auxFinalDate < period.startDate ? auxFinalDate : period.startDate
-    const finalDate = auxFinalDate && auxFinalDate < period.startDate ? undefined : auxFinalDate
-    const aux = { startDate, finalDate } as Period
+    const startDate =
+      value?.startDate && value?.finalDate && auxFinalDate && auxFinalDate < value?.startDate
+        ? auxFinalDate
+        : value?.startDate
+    const finalDate =
+      value?.startDate && value?.finalDate && auxFinalDate && auxFinalDate < value?.startDate ? undefined : auxFinalDate
+
+    const aux = {
+      startDate,
+      finalDate,
+    } as Period
     onChange && onChange(aux)
-    setPeriod(aux)
   }
 
   const onClearStart = () => {
-    const aux = { startDate: undefined, finalDate: period.finalDate } as Period
+    const aux = { startDate: undefined, finalDate: value.finalDate } as Period
     onChange && onChange(aux)
-    setPeriod(aux)
     firstDateFieldRef.current.focus()
   }
 
   const onClearFinal = () => {
-    const aux = { startDate: period.startDate, finalDate: undefined } as Period
+    const aux = { startDate: value.startDate, finalDate: undefined } as Period
     onChange && onChange(aux)
-    setPeriod(aux)
     secondDateFieldRef.current.focus()
   }
 
-  const defaultHandleOnClick = () => {
-    firstDateFieldRef.current.focus()
-  }
+  const defaultHandleOnClick = () => firstDateFieldRef.current.focus()
 
-  const onInputOnFocusInicial = () => {
-    onInputOnFocus && onInputOnFocus(1)
-  }
+  const onInputOnFocusInicial = () => onInputOnFocus && onInputOnFocus(1)
 
-  const onInputOnFocusFinal = () => {
-    onInputOnFocus && onInputOnFocus(2)
-  }
+  const onInputOnFocusFinal = () => onInputOnFocus && onInputOnFocus(2)
 
   const handleIconClick = onIconClick ? onIconClick : defaultHandleOnClick
 
@@ -198,13 +201,14 @@ export function BaseRangeDateInput(props: BaseRangeDateInputProps) {
           <div className={classes.fieldWrapper}>
             <DateInput
               clearable
+              name={name ? `${name}.startDate` : 'startDate'}
               disabled={disabled}
               inputRef={composeRefs(firstDateFieldRef, initialInputRef) as any}
               onChange={onChangeStart}
               onClear={onClearStart}
               placeholder={locale.dateInput.placeholder}
               style={classes.dateField}
-              value={period ? period.startDate : undefined}
+              value={value?.startDate}
               onFocus={onInputOnFocusInicial}
               {...rest}
             />
@@ -215,13 +219,14 @@ export function BaseRangeDateInput(props: BaseRangeDateInputProps) {
           <div className={classes.fieldWrapper}>
             <DateInput
               clearable
+              name={name ? `${name}.finalDate` : 'finalDate'}
               disabled={disabled}
               inputRef={composeRefs(secondDateFieldRef, finalInputRef) as any}
               onChange={onChangeFinal}
               onClear={onClearFinal}
               placeholder={locale.dateInput.placeholder}
               style={classes.dateField}
-              value={period ? period.finalDate : undefined}
+              value={value?.finalDate}
               onFocus={onInputOnFocusFinal}
               {...rest}
             />
diff --git a/src/components/RangeDateField/RangeDateField.tsx b/src/components/RangeDateField/RangeDateField.tsx
index 35556f144..39dc7d74d 100644
--- a/src/components/RangeDateField/RangeDateField.tsx
+++ b/src/components/RangeDateField/RangeDateField.tsx
@@ -25,7 +25,7 @@ export interface RangeDateFieldProps extends Omit<RangeDateInputProps, 'onChange
 }
 
 export function RangeDateField(props: RangeDateFieldProps) {
-  const { onChange, popperProps, minDate, maxDate, value, icon, ...rest } = props
+  const { onChange, popperProps, minDate, maxDate, value, icon, calendarProps, ...rest } = props
 
   const [period, setPeriod] = useState(value ? value : ({} as Period))
   const [periodInputFocus, setPeriodInputFocus] = useState(1)
@@ -40,11 +40,23 @@ export function RangeDateField(props: RangeDateFieldProps) {
 
   useEffect(() => {
     onChange && onChange(period)
-    setPeriod(period)
-  }, [period])
+  }, [onChange, period])
 
   useEffect(() => {
-    const point: Date = handleOnStartPointDateChange()
+    const point = (): Date => {
+      if (periodInputFocus === 1 && period?.startDate) {
+        return period.startDate
+      } else if (periodInputFocus === 2 && period?.finalDate) {
+        return period.finalDate
+      } else if (period?.startDate && !period?.finalDate) {
+        return period.startDate
+      } else if (!period?.startDate && period?.finalDate) {
+        return period.finalDate
+      } else {
+        return new Date()
+      }
+    }
+
     setVisibleDate(point)
   }, [periodInputFocus, period])
 
@@ -67,30 +79,15 @@ export function RangeDateField(props: RangeDateFieldProps) {
   const handleFocusOut = () => setOpen(false)
 
   const handlePeriodChanged = (periodFromBaseInput: Period) => {
-    onChange && onChange(periodFromBaseInput)
     setPeriod(periodFromBaseInput)
   }
 
   const handleCalendarPeriodChanged = (startDate: Date, finalDate: Date) => {
-    onChange && onChange(period)
-    setPeriod({
-      startDate,
-      finalDate,
-    } as Period)
-  }
-
-  const handleOnStartPointDateChange = (): Date => {
-    if (periodInputFocus === 1 && period?.startDate) {
-      return period.startDate
-    } else if (periodInputFocus === 2 && period?.finalDate) {
-      return period.finalDate
-    } else if (period?.startDate && !period?.finalDate) {
-      return period.startDate
-    } else if (!period?.startDate && period?.finalDate) {
-      return period.finalDate
-    } else {
-      return new Date()
-    }
+    startDate && finalDate
+      ? startDate <= finalDate
+        ? setPeriod({ startDate: startDate, finalDate: finalDate } as Period)
+        : setPeriod({ startDate: finalDate, finalDate: startDate } as Period)
+      : setPeriod({ startDate: startDate, finalDate: finalDate } as Period)
   }
 
   const handleOnVisibleDateChange = (vDate: Date): void => setVisibleDate(vDate)
@@ -112,7 +109,7 @@ export function RangeDateField(props: RangeDateFieldProps) {
       {open && (
         <div ref={popupRef} className={css(classes.root, popperStyle)} data-placement={placement} tabIndex={-1}>
           <ControlledRangeDateCalendar
-            values={{ initialDate: period.startDate, finalDate: period.finalDate }}
+            value={{ initialDate: period.startDate, finalDate: period.finalDate }}
             onChange={handleCalendarPeriodChanged}
             onDayClick={handleOnDayClick}
             inputOnFocus={periodInputFocus}
@@ -121,7 +118,7 @@ export function RangeDateField(props: RangeDateFieldProps) {
             modifiers={{
               disabled: disableByRange(minDate, maxDate),
             }}
-            {...props.calendarProps}
+            {...calendarProps}
           />
         </div>
       )}


Test patch:
diff --git a/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.test.tsx b/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.test.tsx
index 3fcfb92c1..a493305f3 100644
--- a/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.test.tsx
+++ b/src/components/Calendar/RangeCalendar/RangeDateCalendar/ControlledRangeDateCalendar.test.tsx
@@ -10,7 +10,7 @@ const createComponent = (props: Partial<ControlledRangeDateCalendarProps> = {})
   <ControlledRangeDateCalendar
     visibleDate={new Date('2019-02-09')}
     onVisibleDateChange={() => new Date('2019-02-09')}
-    values={{
+    value={{
       initialDate: undefined,
       finalDate: undefined,
     }}
@@ -18,12 +18,17 @@ const createComponent = (props: Partial<ControlledRangeDateCalendarProps> = {})
   />
 )
 
-describe('[Calendar][RangeDatePicker]', () => {
+describe('ControlledRangeDateCalendar', () => {
   it('Should render correclty', () => {
     const { container } = render(createComponent())
     expect(container).toMatchSnapshot()
   })
 
+  it('Should render correctly without receiving a value', () => {
+    const { container } = render(createComponent({ value: undefined, inputOnFocus: 1 }))
+    expect(container).toMatchSnapshot()
+  })
+
   it('With empty initialValues, should leave an empty interval', () => {
     const { getAllByRole } = render(createComponent())
     let index = 4
@@ -36,7 +41,7 @@ describe('[Calendar][RangeDatePicker]', () => {
   it('Should select only the initialDate if the finalDate is not defined in initialValues', () => {
     const { getByText } = render(
       createComponent({
-        values: {
+        value: {
           initialDate: new Date('2019-02-11'),
           finalDate: undefined,
         },
@@ -52,7 +57,7 @@ describe('[Calendar][RangeDatePicker]', () => {
   it('Should select only the finalDate if the finalDate is setted in initialValues', () => {
     const { getByText } = render(
       createComponent({
-        values: {
+        value: {
           initialDate: undefined,
           finalDate: new Date('2019-02-11'),
         },
@@ -67,7 +72,7 @@ describe('[Calendar][RangeDatePicker]', () => {
   it('With initialValues should select the interval', () => {
     const { getByText } = render(
       createComponent({
-        values: {
+        value: {
           initialDate: new Date('2019-02-11'),
           finalDate: new Date('2019-02-13'),
         },
@@ -81,111 +86,90 @@ describe('[Calendar][RangeDatePicker]', () => {
     expect(getByText('14').getAttribute('aria-selected')).toBe('false')
   })
 
-  it('Clicks on the same day, should fill initial (final has the same behavior) date with the same value', () => {
-    const { getByText } = render(createComponent({ inputOnFocus: 1 }))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
+  it('Clicks on the same day, should fill initial (final has the same behavior) date with the same value', async () => {
+    const change = jest.fn()
+    const { getByText } = render(createComponent({ onChange: change, inputOnFocus: 1 }))
 
     fireEvent.click(getByText('10'))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-10'), undefined)
 
     fireEvent.click(getByText('10'))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-10'), undefined)
 
     fireEvent.click(getByText('11'))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('true')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-11'), undefined)
   })
 
-  it('Should select the finalDate correctly, with a predefined initialDate', async () => {
+  it('Should select the finalDate correctly, with a predefined initialDate', () => {
+    const change = jest.fn()
     const { getByText } = render(
       createComponent({
-        values: {
+        value: {
           initialDate: new Date('2019-02-11'),
           finalDate: undefined,
         },
+        onChange: change,
         inputOnFocus: 2,
       })
     )
 
-    expect(getByText('11').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('12').getAttribute('aria-selected')).toBe('false')
-
     fireEvent.click(getByText('12'))
-    expect(getByText('11').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('12').getAttribute('aria-selected')).toBe('true')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-11'), new Date('2019-02-12'))
   })
 
   it('Should select correctly both initialDate and finalDate, without a predefined interval', () => {
-    const { rerender, getByText } = render(createComponent({ inputOnFocus: 1 }))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
+    const change = jest.fn()
+    const { rerender, getByText } = render(createComponent({ onChange: change, inputOnFocus: 1 }))
 
     fireEvent.click(getByText('10'))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-10'), undefined)
 
     rerender(
       createComponent({
-        values: {
+        value: {
           initialDate: new Date('2019-02-10'),
           finalDate: undefined,
         },
+        onChange: change,
         inputOnFocus: 2,
       })
     )
 
     fireEvent.click(getByText('11'))
-    expect(getByText('10').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('11').getAttribute('aria-selected')).toBe('true')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-10'), new Date('2019-02-11'))
   })
 
   it('Should select correctly both initialDate and finalDate, with a predefined interval', () => {
-    let initial: Date
-    let final: Date
+    const change = jest.fn()
     const { rerender, getByText } = render(
       createComponent({
-        values: {
+        value: {
           initialDate: new Date('2019-02-11'),
           finalDate: new Date('2019-02-12'),
         },
+        onChange: change,
         inputOnFocus: 1,
-        onChange: (i: Date, f: Date) => {
-          initial = i
-          final = f
-        },
       })
     )
-
-    expect(getByText('11').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('12').getAttribute('aria-selected')).toBe('true')
-
     fireEvent.click(getByText('20'))
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('12').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('21').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-20'), undefined)
 
     rerender(
       createComponent({
-        values: {
-          initialDate: initial,
-          finalDate: final,
+        value: {
+          initialDate: new Date('2019-02-20'),
+          finalDate: undefined,
         },
+        onChange: change,
         inputOnFocus: 2,
       })
     )
 
     fireEvent.click(getByText('21'))
-    expect(getByText('11').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('12').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('21').getAttribute('aria-selected')).toBe('true')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-20'), new Date('2019-02-21'))
   })
 
-  it('Component should call onChange on every update of the values', async () => {
+  it('Component should call onChange on every update of the value', async () => {
     const spy = jest.fn()
     const { getByText } = render(createComponent({ onChange: spy, inputOnFocus: 1 }))
 
@@ -199,79 +183,94 @@ describe('[Calendar][RangeDatePicker]', () => {
   })
 
   it('should change only start date when focus is in first input and the selected date is before start date', () => {
+    const change = jest.fn()
     const { getByText } = render(
       createComponent({
-        values: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        value: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        onChange: change,
         inputOnFocus: 1,
       })
     )
-    expect(getByText('14').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('15').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('false')
-
     fireEvent.click(getByText('10'))
-    expect(getByText('09').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('10').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('15').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-10'), new Date('2019-02-19'))
   })
 
   it('should start a new period when focus is in first input and the selected date is after final date', () => {
+    const change = jest.fn()
     const { getByText } = render(
       createComponent({
-        values: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        value: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        onChange: change,
         inputOnFocus: 1,
       })
     )
-    expect(getByText('14').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('15').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('false')
-
     fireEvent.click(getByText('21'))
-    expect(getByText('15').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('21').getAttribute('aria-selected')).toBe('true')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-21'), undefined)
   })
 
   it('should start a new period when focus is in second input and the selected date is before start date', () => {
+    const change = jest.fn()
     const { getByText } = render(
       createComponent({
-        values: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        value: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        onChange: change,
         inputOnFocus: 2,
       })
     )
-    expect(getByText('14').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('15').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('false')
-
     fireEvent.click(getByText('10'))
-    expect(getByText('09').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('10').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('15').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-10'), undefined)
   })
 
   it('should change only final date when focus is in second input and the selected date is after final date', () => {
+    const change = jest.fn()
     const { getByText } = render(
       createComponent({
-        values: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        value: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-19') },
+        onChange: change,
         inputOnFocus: 2,
       })
     )
-    expect(getByText('14').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('15').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('20').getAttribute('aria-selected')).toBe('false')
-
     fireEvent.click(getByText('23'))
-    expect(getByText('14').getAttribute('aria-selected')).toBe('false')
-    expect(getByText('19').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('21').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('23').getAttribute('aria-selected')).toBe('true')
-    expect(getByText('24').getAttribute('aria-selected')).toBe('false')
+    expect(change).toHaveBeenLastCalledWith(new Date('2019-02-15'), new Date('2019-02-23'))
+  })
+
+  describe('should select correctly the received values', () => {
+    it('should select only initialDate', () => {
+      const { getByText } = render(
+        createComponent({
+          value: { initialDate: new Date('2019-02-15'), finalDate: undefined },
+          inputOnFocus: 1,
+        })
+      )
+
+      expect(getByText('14').getAttribute('aria-selected')).toBe('false')
+      expect(getByText('15').getAttribute('aria-selected')).toBe('true')
+      expect(getByText('16').getAttribute('aria-selected')).toBe('false')
+    })
+
+    it('should select only finalDate', () => {
+      const { getByText } = render(
+        createComponent({
+          value: { initialDate: undefined, finalDate: new Date('2019-02-18') },
+          inputOnFocus: 2,
+        })
+      )
+      expect(getByText('17').getAttribute('aria-selected')).toBe('false')
+      expect(getByText('18').getAttribute('aria-selected')).toBe('true')
+      expect(getByText('19').getAttribute('aria-selected')).toBe('false')
+    })
+
+    it('should select the received range', () => {
+      const { getByText } = render(
+        createComponent({
+          value: { initialDate: new Date('2019-02-15'), finalDate: new Date('2019-02-22') },
+          inputOnFocus: 2,
+        })
+      )
+      expect(getByText('14').getAttribute('aria-selected')).toBe('false')
+      expect(getByText('15').getAttribute('aria-selected')).toBe('true')
+      expect(getByText('22').getAttribute('aria-selected')).toBe('true')
+      expect(getByText('23').getAttribute('aria-selected')).toBe('false')
+    })
   })
 })
diff --git a/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.test.tsx b/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.test.tsx
index 7b85ff588..341900b10 100644
--- a/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.test.tsx
+++ b/src/components/Calendar/RangeCalendar/RangeDateCalendar/RangeDateCalendar.test.tsx
@@ -15,6 +15,7 @@ const createComponent = (props: Partial<RangeDateCalendarProps> = {}) => (
     onVisibleDateChange={jest.fn()}
     initialDate={undefined}
     finalDate={undefined}
+    inputOnFocus={1}
     {...props}
   />
 )
@@ -36,7 +37,7 @@ const iterateObjectFields = (obj: Object, testFn: (fieldName: string, fieldValue
   }
 }
 
-describe('[Calendar][RangeDatePicker]', () => {
+describe('RangeDateCalendar', () => {
   const theme = createTheme()
   const normalizeCssClassNames = (str: string) => str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
   describe('Selection and hover', () => {
diff --git a/src/components/Calendar/RangeCalendar/RangeDateCalendar/__snapshots__/ControlledRangeDateCalendar.test.tsx.snap b/src/components/Calendar/RangeCalendar/RangeDateCalendar/__snapshots__/ControlledRangeDateCalendar.test.tsx.snap
index c75b20ba0..6e060a883 100644
--- a/src/components/Calendar/RangeCalendar/RangeDateCalendar/__snapshots__/ControlledRangeDateCalendar.test.tsx.snap
+++ b/src/components/Calendar/RangeCalendar/RangeDateCalendar/__snapshots__/ControlledRangeDateCalendar.test.tsx.snap
@@ -1,6 +1,665 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`[Calendar][RangeDatePicker] Should render correclty 1`] = `
+exports[`ControlledRangeDateCalendar Should render correclty 1`] = `
+.emotion-47 {
+  width: 288px;
+}
+
+.emotion-10 {
+  display: grid;
+  grid-auto-flow: column;
+  grid-auto-columns: minmax(min-content,max-content);
+  grid-gap: 0.5rem;
+  -webkit-box-pack: space-around;
+  -webkit-justify-content: space-around;
+  -ms-flex-pack: space-around;
+  justify-content: space-around;
+  margin-bottom: 0.5rem;
+  font-weight: bold;
+}
+
+.emotion-4 {
+  display: grid;
+  grid-auto-flow: column;
+  grid-auto-columns: minmax(min-content,max-content);
+  grid-gap: 0.5rem;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+}
+
+.emotion-1 {
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1.5rem;
+  color: #3A3A47;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  position: relative;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-transition: all .2s;
+  transition: all .2s;
+  font-weight: bold;
+  cursor: pointer;
+  background-color: transparent;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  color: #3A3A47;
+  -webkit-text-decoration: none;
+  text-decoration: none;
+  font-size: 0.875rem;
+  padding: calc(0.25rem - 1px) calc(0.5rem - 1px);
+}
+
+.emotion-1 > span {
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+}
+
+.emotion-1:not(:disabled):active {
+  box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
+}
+
+.emotion-1:focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #0069D0;
+}
+
+.emotion-1:not(:disabled):hover {
+  background-color: rgba(58,58,71,0.1);
+}
+
+.emotion-0 {
+  fill: currentColor;
+  font-size: 1.5rem;
+}
+
+.emotion-46 {
+  border-collapse: collapse;
+  text-align: center;
+  line-height: 1.5rem;
+  width: 100%;
+}
+
+.emotion-46 th {
+  width: 2rem;
+  padding: 0.25rem 0;
+}
+
+.emotion-16 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+}
+
+.emotion-16:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+.emotion-11 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+  color: #AAAAB9;
+}
+
+.emotion-11:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+<div>
+  <div
+    class="emotion-47"
+  >
+    <div
+      class="emotion-10"
+    >
+      <div
+        class="emotion-4"
+      >
+        <button
+          class="emotion-1"
+          tabindex="-1"
+          title="Previous month"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-0"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M14.707 16.294a1 1 0 11-1.414 1.414l-5-5a1 1 0 010-1.414l5.001-5.001a1 1 0 011.414 1.414l-4.294 4.294 4.293 4.293z"
+              />
+            </svg>
+          </span>
+        </button>
+        Feb
+        <button
+          class="emotion-1"
+          tabindex="-1"
+          title="Next month"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-0"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M8.294 7.707a1 1 0 111.414-1.414l5 5a1 1 0 010 1.414l-5 5.001a1 1 0 01-1.415-1.414L12.587 12 8.294 7.707z"
+              />
+            </svg>
+          </span>
+        </button>
+      </div>
+      <div
+        class="emotion-4"
+      >
+        <button
+          class="emotion-1"
+          tabindex="-1"
+          title="Previous year"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-0"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M14.707 16.294a1 1 0 11-1.414 1.414l-5-5a1 1 0 010-1.414l5.001-5.001a1 1 0 011.414 1.414l-4.294 4.294 4.293 4.293z"
+              />
+            </svg>
+          </span>
+        </button>
+        2019
+        <button
+          class="emotion-1"
+          tabindex="-1"
+          title="Next year"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-0"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M8.294 7.707a1 1 0 111.414-1.414l5 5a1 1 0 010 1.414l-5 5.001a1 1 0 01-1.415-1.414L12.587 12 8.294 7.707z"
+              />
+            </svg>
+          </span>
+        </button>
+      </div>
+    </div>
+    <table
+      class="emotion-46"
+    >
+      <thead>
+        <tr>
+          <th>
+            S
+          </th>
+          <th>
+            M
+          </th>
+          <th>
+            T
+          </th>
+          <th>
+            W
+          </th>
+          <th>
+            T
+          </th>
+          <th>
+            F
+          </th>
+          <th>
+            S
+          </th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td
+            data-date="2019-01-27"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              27
+            </span>
+          </td>
+          <td
+            data-date="2019-01-28"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              28
+            </span>
+          </td>
+          <td
+            data-date="2019-01-29"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              29
+            </span>
+          </td>
+          <td
+            data-date="2019-01-30"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              30
+            </span>
+          </td>
+          <td
+            data-date="2019-01-31"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              31
+            </span>
+          </td>
+          <td
+            data-date="2019-02-01"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              01
+            </span>
+          </td>
+          <td
+            data-date="2019-02-02"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              02
+            </span>
+          </td>
+        </tr>
+        <tr>
+          <td
+            data-date="2019-02-03"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              03
+            </span>
+          </td>
+          <td
+            data-date="2019-02-04"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              04
+            </span>
+          </td>
+          <td
+            data-date="2019-02-05"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              05
+            </span>
+          </td>
+          <td
+            data-date="2019-02-06"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              06
+            </span>
+          </td>
+          <td
+            data-date="2019-02-07"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              07
+            </span>
+          </td>
+          <td
+            data-date="2019-02-08"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              08
+            </span>
+          </td>
+          <td
+            data-date="2019-02-09"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              09
+            </span>
+          </td>
+        </tr>
+        <tr>
+          <td
+            data-date="2019-02-10"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              10
+            </span>
+          </td>
+          <td
+            data-date="2019-02-11"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              11
+            </span>
+          </td>
+          <td
+            data-date="2019-02-12"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              12
+            </span>
+          </td>
+          <td
+            data-date="2019-02-13"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              13
+            </span>
+          </td>
+          <td
+            data-date="2019-02-14"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              14
+            </span>
+          </td>
+          <td
+            data-date="2019-02-15"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              15
+            </span>
+          </td>
+          <td
+            data-date="2019-02-16"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              16
+            </span>
+          </td>
+        </tr>
+        <tr>
+          <td
+            data-date="2019-02-17"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              17
+            </span>
+          </td>
+          <td
+            data-date="2019-02-18"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              18
+            </span>
+          </td>
+          <td
+            data-date="2019-02-19"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              19
+            </span>
+          </td>
+          <td
+            data-date="2019-02-20"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              20
+            </span>
+          </td>
+          <td
+            data-date="2019-02-21"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              21
+            </span>
+          </td>
+          <td
+            data-date="2019-02-22"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              22
+            </span>
+          </td>
+          <td
+            data-date="2019-02-23"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              23
+            </span>
+          </td>
+        </tr>
+        <tr>
+          <td
+            data-date="2019-02-24"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              24
+            </span>
+          </td>
+          <td
+            data-date="2019-02-25"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              25
+            </span>
+          </td>
+          <td
+            data-date="2019-02-26"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              26
+            </span>
+          </td>
+          <td
+            data-date="2019-02-27"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              27
+            </span>
+          </td>
+          <td
+            data-date="2019-02-28"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-16"
+              role="button"
+            >
+              28
+            </span>
+          </td>
+          <td
+            data-date="2019-03-01"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              01
+            </span>
+          </td>
+          <td
+            data-date="2019-03-02"
+          >
+            <span
+              aria-selected="false"
+              class="emotion-11"
+              role="button"
+            >
+              02
+            </span>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</div>
+`;
+
+exports[`ControlledRangeDateCalendar Should render correctly without receiving a value 1`] = `
 .emotion-47 {
   width: 288px;
 }
diff --git a/src/components/RangeDateField/BaseRangeDateInput.test.tsx b/src/components/RangeDateField/BaseRangeDateInput.test.tsx
index e9aa9bcaf..8a15a0ad3 100644
--- a/src/components/RangeDateField/BaseRangeDateInput.test.tsx
+++ b/src/components/RangeDateField/BaseRangeDateInput.test.tsx
@@ -1,15 +1,16 @@
-import { fireEvent, render, wait } from '@testing-library/react'
+import { fireEvent, render } from '@testing-library/react'
 import React from 'react'
 
 import { LocaleContext } from '../../i18n'
 import ptBr from '../../i18n/locales/pt-BR'
+import enUs from '../../i18n/locales/en-US'
 
 import { BaseRangeDateInput, Period } from './BaseRangeDateInput'
 
 const FIRST_INPUT = 0
 const SECOND_INPUT = 1
 
-describe('PeriodInput', () => {
+describe('BaseRangeDateInput', () => {
   describe('render', () => {
     it('should render correctly', () => {
       const { container } = render(<BaseRangeDateInput />)
@@ -27,14 +28,24 @@ describe('PeriodInput', () => {
     })
   })
 
+  describe('on click', () => {
+    it('should set focus on startDate input when calendar button is clicked', () => {
+      const { container } = render(<BaseRangeDateInput />)
+      const button = container.querySelector('button')
+      const inputs = container.querySelectorAll('input')
+      fireEvent.click(button)
+      expect(inputs[0]).toEqual(document.activeElement)
+      expect(inputs[1]).not.toEqual(document.activeElement)
+    })
+  })
+
   describe('format', () => {
-    it('should accept and format period as value', async () => {
+    it('should accept and format period as value', () => {
       const { container } = render(
         <BaseRangeDateInput
           value={{ startDate: new Date('2019-01-01'), finalDate: new Date('2019-02-02') } as Period}
         />
       )
-      await wait()
       const inputs = container.querySelectorAll('input')
       expect(inputs[FIRST_INPUT].value).toEqual('01/01/2019')
       expect(inputs[SECOND_INPUT].value).toEqual('02/02/2019')
@@ -42,21 +53,16 @@ describe('PeriodInput', () => {
   })
 
   describe('change actions', () => {
-    it('should call onChange with finalDate as undefined when second input is cleared', async () => {
+    it('should call onChange with finalDate as undefined when second input is cleared', () => {
       const change = jest.fn()
-
       const { container } = render(
         <BaseRangeDateInput
           onChange={change}
           value={{ startDate: new Date('2019-01-01'), finalDate: new Date('2019-02-02') } as Period}
         />
       )
-
-      await wait()
       const inputs = container.querySelectorAll('input')
       fireEvent.change(inputs[SECOND_INPUT], { target: { value: '' } })
-      await wait()
-
       expect(change).toHaveBeenLastCalledWith({
         startDate: new Date('2019-01-01'),
         finalDate: null,
@@ -65,36 +71,115 @@ describe('PeriodInput', () => {
   })
 
   describe('validate entry', () => {
-    it('should call onChange only when a valid date is typed', async () => {
+    it(`should't call onChange only when a valid date is typed`, () => {
       const change = jest.fn()
       const { container } = render(<BaseRangeDateInput onChange={change} />)
 
-      await wait()
       const inputs = container.querySelectorAll('input')
 
       fireEvent.change(inputs[FIRST_INPUT], { target: { value: '01/01/201' } })
-      await wait()
-      expect(change).toHaveBeenLastCalledWith(undefined)
+      expect(change).not.toBeCalled()
 
       fireEvent.change(inputs[FIRST_INPUT], { target: { value: '01/01/2019' } })
-      await wait()
       expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2019-01-01'), finalDate: undefined } as Period)
 
       fireEvent.change(inputs[SECOND_INPUT], { target: { value: '01/01/201' } })
-      await wait()
       expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2019-01-01'), finalDate: undefined } as Period)
 
       fireEvent.change(inputs[SECOND_INPUT], { target: { value: '02/02/2019' } })
-      await wait()
       expect(change).toHaveBeenLastCalledWith({
-        startDate: new Date('2019-01-01'),
+        startDate: undefined,
         finalDate: new Date('2019-02-02'),
       } as Period)
     })
+
+    it(`should call onChange with undefined when a invalid date is typed (before minDate and after maxDate)`, () => {
+      const change = jest.fn()
+      const { container } = render(
+        <BaseRangeDateInput onChange={change} minDate={new Date('2019-01-10')} maxDate={new Date('2019-01-15')} />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '09/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: undefined } as Period)
+
+      fireEvent.change(inputs[SECOND_INPUT], { target: { value: '16/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: undefined } as Period)
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '13/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({
+        startDate: new Date('2019-01-13'),
+        finalDate: undefined,
+      } as Period)
+    })
+
+    it(`should call onChange with undefined when a invalid date is typed before minDate`, () => {
+      const change = jest.fn()
+      const { container } = render(<BaseRangeDateInput onChange={change} minDate={new Date('2019-01-10')} />)
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '09/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: undefined } as Period)
+
+      fireEvent.change(inputs[SECOND_INPUT], { target: { value: '16/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: new Date('2019-01-16') } as Period)
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '13/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({
+        startDate: new Date('2019-01-13'),
+        finalDate: undefined,
+      } as Period)
+    })
+
+    it(`should call onChange with undefined when a invalid date is typed after maxDate`, () => {
+      const change = jest.fn()
+      const { container } = render(<BaseRangeDateInput onChange={change} maxDate={new Date('2019-01-15')} />)
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '09/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2019-01-09'), finalDate: undefined } as Period)
+
+      fireEvent.change(inputs[SECOND_INPUT], { target: { value: '16/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: undefined } as Period)
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '13/01/2019' } })
+      expect(change).toHaveBeenLastCalledWith({
+        startDate: new Date('2019-01-13'),
+        finalDate: undefined,
+      } as Period)
+    })
+
+    it(`should call onChange with only new startDate when finalDate value is typed and it's before startDate`, () => {
+      const change = jest.fn()
+      const { container } = render(
+        <BaseRangeDateInput
+          onChange={change}
+          value={{ startDate: new Date('2019-01-01'), finalDate: new Date('2019-02-02') } as Period}
+        />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.change(inputs[SECOND_INPUT], { target: { value: '01/12/2018' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2018-12-01'), finalDate: undefined } as Period)
+    })
+
+    it(`should call onChange with only new startDate dates when startDate value is typed and it's after finalDate`, () => {
+      const change = jest.fn()
+      const { container } = render(
+        <BaseRangeDateInput
+          onChange={change}
+          value={{ startDate: new Date('2019-01-01'), finalDate: new Date('2019-02-02') } as Period}
+        />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.change(inputs[FIRST_INPUT], { target: { value: '10/02/2019' } })
+      expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2019-02-10'), finalDate: undefined } as Period)
+    })
   })
 
   describe('clear actions', () => {
-    it('should clear only second input when click clear in second input', async () => {
+    it('should clear only second input when click clear in second input', () => {
       const change = jest.fn()
       const { container } = render(
         <BaseRangeDateInput
@@ -102,18 +187,13 @@ describe('PeriodInput', () => {
           onChange={change}
         />
       )
-      await wait()
-
       const spans = container.querySelectorAll('span')
       const span = spans[SECOND_INPUT + 1]
       fireEvent.click(span)
-
-      await wait()
-
       expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2019-01-01'), finalDate: undefined } as Period)
     })
 
-    it('should clear only first input when click clear in first input', async () => {
+    it('should clear only first input when click clear in first input', () => {
       const change = jest.fn()
       const { container } = render(
         <BaseRangeDateInput
@@ -121,26 +201,59 @@ describe('PeriodInput', () => {
           onChange={change}
         />
       )
-      await wait()
-
       const spans = container.querySelectorAll('span')
       const span = spans[FIRST_INPUT]
       fireEvent.click(span)
-
-      await wait()
-
       expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: new Date('2019-02-02') } as Period)
     })
   })
 
   describe('customization', () => {
-    it('should allow placeholder customization via locale context', () => {
+    it('should allow ptBR placeholder customization via locale context', () => {
       const { container } = render(
         <LocaleContext.Provider value={ptBr}>
           <BaseRangeDateInput />
         </LocaleContext.Provider>
       )
       expect(container.querySelector('input').getAttribute('placeholder')).toEqual(ptBr.dateInput.placeholder)
+      expect(container).toMatchSnapshot()
+    })
+
+    it('should allow enUS placeholder customization via locale context', () => {
+      const { container } = render(
+        <LocaleContext.Provider value={enUs}>
+          <BaseRangeDateInput />
+        </LocaleContext.Provider>
+      )
+      expect(container.querySelector('input').getAttribute('placeholder')).toEqual(enUs.dateInput.placeholder)
+      expect(container).toMatchSnapshot()
+    })
+
+    it('should allow ptBr i18n in range separator', () => {
+      const { container } = render(
+        <LocaleContext.Provider value={ptBr}>
+          <BaseRangeDateInput />
+        </LocaleContext.Provider>
+      )
+      expect(container.querySelector('span').textContent).toEqual(ptBr.rangeDateField.separator)
+      expect(container).toMatchSnapshot()
+    })
+
+    it('should allow enUs i18n in range separator', () => {
+      const { container } = render(
+        <LocaleContext.Provider value={enUs}>
+          <BaseRangeDateInput />
+        </LocaleContext.Provider>
+      )
+      expect(container.querySelector('span').textContent).toEqual(enUs.rangeDateField.separator)
+      expect(container).toMatchSnapshot()
+    })
+
+    it('should be possible to set a name to inputs', () => {
+      const name = 'baseRangeDate'
+      const { container } = render(<BaseRangeDateInput name={name} />)
+      expect(container.querySelectorAll('input')[0].getAttribute('name')).toEqual(name + '.startDate')
+      expect(container.querySelectorAll('input')[1].getAttribute('name')).toEqual(name + '.finalDate')
     })
   })
 })
diff --git a/src/components/RangeDateField/RangeDateField.test.tsx b/src/components/RangeDateField/RangeDateField.test.tsx
index c061d83a1..b54d85a28 100644
--- a/src/components/RangeDateField/RangeDateField.test.tsx
+++ b/src/components/RangeDateField/RangeDateField.test.tsx
@@ -5,8 +5,9 @@ import * as DateFieldModule from '../DateField/DateField'
 import { disableByRange } from '../DateField/DateField'
 
 import { RangeDateField } from './RangeDateField'
+import { Period } from './BaseRangeDateInput'
 
-describe('PeriodField', () => {
+describe('RangeDateField', () => {
   describe('render', () => {
     it('should render correctly', () => {
       const { container } = render(<RangeDateField />)
@@ -14,9 +15,7 @@ describe('PeriodField', () => {
     })
 
     it('should render correctly when opened', () => {
-      const { container } = render(
-        <RangeDateField onChange={jest.fn()} calendarProps={{ visibleDate: new Date('2018-10-01') }} />
-      )
+      const { container } = render(<RangeDateField calendarProps={{ visibleDate: new Date('2018-10-01') }} />)
       fireEvent.focus(container.querySelector('input'))
       expect(container).toMatchSnapshot()
     })
@@ -30,6 +29,212 @@ describe('PeriodField', () => {
       const { container } = render(<RangeDateField invalid />)
       expect(container).toMatchSnapshot()
     })
+
+    it('should show calendar correctly when inputs are cleaned', () => {
+      const { container } = render(<RangeDateField calendarProps={{ visibleDate: new Date('2018-10-01') }} />)
+
+      fireEvent.focus(container.querySelector('input'))
+      expect(container.querySelector('[data-date="2018-10-01"] span')).toMatchSnapshot()
+    })
+
+    it('should show calendar correctly when only startDate is defined and is focused', () => {
+      const { container } = render(
+        <RangeDateField value={{ startDate: new Date('2018-10-01'), finalDate: undefined }} />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.focus(inputs[0])
+      expect(container.querySelector('[data-date="2018-10-01"] span')).toMatchSnapshot()
+      expect(container.querySelector('[data-date="2018-11-15"] span')).toThrowErrorMatchingSnapshot()
+    })
+
+    it('should show calendar correctly when only finalDate is defined and is focused', () => {
+      const { container } = render(
+        <RangeDateField value={{ startDate: undefined, finalDate: new Date('2018-10-01') }} />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.focus(inputs[1])
+      expect(container.querySelector('[data-date="2018-10-01"] span')).toMatchSnapshot()
+      expect(container.querySelector('[data-date="2018-11-15"] span')).toThrowErrorMatchingSnapshot()
+    })
+
+    it('should show calendar correctly when startDate and finalDate are defined and startDate is focused', () => {
+      const { container } = render(
+        <RangeDateField value={{ startDate: new Date('2018-10-01'), finalDate: new Date('2018-11-15') }} />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.focus(inputs[0])
+      expect(container.querySelector('[data-date="2018-10-01"] span')).toMatchSnapshot()
+      expect(container.querySelector('[data-date="2018-11-15"] span')).toThrowErrorMatchingSnapshot()
+    })
+
+    it('should show calendar correctly when startDate and finalDate are defined and finalDate is focused', () => {
+      const { container } = render(
+        <RangeDateField value={{ startDate: new Date('2018-10-01'), finalDate: new Date('2018-11-15') }} />
+      )
+      const inputs = container.querySelectorAll('input')
+
+      fireEvent.focus(inputs[1])
+      expect(container.querySelector('[data-date="2018-10-01"] span')).toThrowErrorMatchingSnapshot()
+      expect(container.querySelector('[data-date="2018-11-15"] span')).toMatchSnapshot()
+    })
+  })
+
+  describe('onChange calls', () => {
+    describe('typing on the inputs', () => {
+      it('should call onChange when a date is typed (in startDate or finalDate)', () => {
+        const change = jest.fn()
+        const { container } = render(
+          <RangeDateField onChange={change} calendarProps={{ visibleDate: new Date('2018-10-01') }} />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.change(inputs[0], { target: { value: '01/10/2018' } })
+        expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2018-10-01'), finalDate: undefined } as Period)
+
+        fireEvent.change(inputs[1], { target: { value: '01/11/2018' } })
+        expect(change).toHaveBeenLastCalledWith({
+          startDate: new Date('2018-10-01'),
+          finalDate: new Date('2018-11-01'),
+        } as Period)
+      })
+    })
+
+    describe('clicking on the calendar', () => {
+      it('should call onchange with only startDate defined when startDate input has focus and a date is select on calendar', () => {
+        const change = jest.fn()
+        const { container, getByText } = render(
+          <RangeDateField onChange={change} calendarProps={{ visibleDate: new Date('2018-10-01') }} />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[0])
+        fireEvent.click(getByText('05'))
+        expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2018-10-05'), finalDate: undefined } as Period)
+      })
+    })
+
+    describe('clicking on the calendar', () => {
+      it('should call onchange with only finalDate defined when finalDate input has focus and a date is select on calendar', () => {
+        const change = jest.fn()
+        const { container, getByText } = render(
+          <RangeDateField onChange={change} calendarProps={{ visibleDate: new Date('2018-10-01') }} />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[1])
+        fireEvent.click(getByText('05'))
+        expect(change).toHaveBeenLastCalledWith({ startDate: undefined, finalDate: new Date('2018-10-05') } as Period)
+      })
+
+      it('should call onchange with only startDate defined when startDate input has focus and the selected date is after finalDate value', () => {
+        const change = jest.fn()
+        const { container, getByText, getByTitle } = render(
+          <RangeDateField
+            onChange={change}
+            value={{ startDate: new Date('2018-10-01'), finalDate: new Date('2018-11-15') }}
+          />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[0])
+        fireEvent.click(getByTitle('Next month'))
+        fireEvent.click(getByText('20'))
+        expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2018-11-20'), finalDate: undefined } as Period)
+      })
+
+      it('should call onchange with only startDate defined when finalDate input has focus and the selected date is before startDate value', () => {
+        const change = jest.fn()
+        const { container, getByText, getByTitle } = render(
+          <RangeDateField
+            onChange={change}
+            value={{ startDate: new Date('2018-10-10'), finalDate: new Date('2018-11-15') }}
+          />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[1])
+        fireEvent.click(getByTitle('Previous month'))
+        fireEvent.click(getByText('05'))
+        expect(change).toHaveBeenLastCalledWith({ startDate: new Date('2018-10-05'), finalDate: undefined } as Period)
+      })
+
+      it('should call onchange with a new finalDate when finalDate input has focus and the selected date is after his value', () => {
+        const change = jest.fn()
+        const { container, getByText } = render(
+          <RangeDateField
+            onChange={change}
+            value={{ startDate: new Date('2018-10-01'), finalDate: new Date('2018-11-15') }}
+          />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[1])
+        fireEvent.click(getByText('20'))
+        expect(change).toHaveBeenLastCalledWith({
+          startDate: new Date('2018-10-01'),
+          finalDate: new Date('2018-11-20'),
+        } as Period)
+      })
+
+      it('should call onchange with a new startDate when startDate input has focus and the selected date is before his value', () => {
+        const change = jest.fn()
+        const { container, getByText } = render(
+          <RangeDateField
+            onChange={change}
+            value={{ startDate: new Date('2018-10-10'), finalDate: new Date('2018-11-15') }}
+          />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[0])
+        fireEvent.click(getByText('05'))
+        expect(change).toHaveBeenLastCalledWith({
+          startDate: new Date('2018-10-05'),
+          finalDate: new Date('2018-11-15'),
+        } as Period)
+      })
+
+      it('should call onchange with switched dates when finalDate input has focus and the selected date is before startDate', () => {
+        const change = jest.fn()
+        const { container, getByText } = render(
+          <RangeDateField
+            onChange={change}
+            value={{ startDate: new Date('2018-10-10'), finalDate: undefined }}
+            calendarProps={{ visibleDate: new Date('2018-09-15') }}
+          />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[1])
+        fireEvent.click(getByText('10'))
+        expect(change).toHaveBeenLastCalledWith({
+          startDate: new Date('2018-09-10'),
+          finalDate: new Date('2018-10-10'),
+        } as Period)
+      })
+
+      it('should call onchange with switched dates when startDate input has focus and the selected date is after finalDate', () => {
+        const change = jest.fn()
+        const { container, getByText } = render(
+          <RangeDateField
+            onChange={change}
+            value={{ startDate: undefined, finalDate: new Date('2018-10-10') }}
+            calendarProps={{ visibleDate: new Date('2018-09-15') }}
+          />
+        )
+        const inputs = container.querySelectorAll('input')
+
+        fireEvent.focus(inputs[0])
+        fireEvent.click(getByText('10'))
+        expect(change).toHaveBeenLastCalledWith({
+          startDate: new Date('2018-09-10'),
+          finalDate: new Date('2018-10-10'),
+        } as Period)
+      })
+    })
   })
 })
 
diff --git a/src/components/RangeDateField/__snapshots__/BaseRangeDateInput.test.tsx.snap b/src/components/RangeDateField/__snapshots__/BaseRangeDateInput.test.tsx.snap
index f15b2e361..aadea6169 100644
--- a/src/components/RangeDateField/__snapshots__/BaseRangeDateInput.test.tsx.snap
+++ b/src/components/RangeDateField/__snapshots__/BaseRangeDateInput.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`PeriodInput render should render correctly 1`] = `
+exports[`BaseRangeDateInput customization should allow enUS placeholder customization via locale context 1`] = `
 .emotion-9 {
   background-color: #FFFFFF;
   border: 1px solid#AAAAB9;
@@ -266,6 +266,7 @@ exports[`PeriodInput render should render correctly 1`] = `
               <input
                 autocomplete="off"
                 class="emotion-0"
+                name="startDate"
                 placeholder="mm/dd/yyyy"
                 type="text"
                 value=""
@@ -292,6 +293,7 @@ exports[`PeriodInput render should render correctly 1`] = `
               <input
                 autocomplete="off"
                 class="emotion-0"
+                name="finalDate"
                 placeholder="mm/dd/yyyy"
                 type="text"
                 value=""
@@ -329,7 +331,1331 @@ exports[`PeriodInput render should render correctly 1`] = `
 </div>
 `;
 
-exports[`PeriodInput render should render correctly when disabled 1`] = `
+exports[`BaseRangeDateInput customization should allow enUs i18n in range separator 1`] = `
+.emotion-9 {
+  background-color: #FFFFFF;
+  border: 1px solid#AAAAB9;
+  border-radius: 2px;
+  cursor: default;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  position: relative;
+  padding-right: 2.5rem;
+  padding-left: 0.1rem;
+  -webkit-transition: box-shadow .2s ease;
+  transition: box-shadow .2s ease;
+}
+
+.emotion-9:required {
+  box-shadow: none;
+}
+
+.emotion-9:not(:disabled):hover {
+  border-color: #8F8FA2;
+}
+
+.emotion-9:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-9:focus-within:not(:disabled) {
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+  outline: none;
+}
+
+.emotion-4 {
+  cursor: default;
+  background: transparent;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+}
+
+.emotion-3 {
+  -webkit-flex: 1;
+  -ms-flex: 1;
+  flex: 1;
+}
+
+.emotion-13 {
+  position: relative;
+}
+
+.emotion-13 input {
+  padding-right: 3rem;
+}
+
+.emotion-12 {
+  position: absolute;
+  background-color: #F0F0F5;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  padding: 0.25rem;
+  width: 2.5rem;
+  top: 1px;
+  bottom: 1px;
+  right: 1px;
+}
+
+.emotion-1 {
+  position: relative;
+}
+
+.emotion-0 {
+  background-color: #FFFFFF;
+  border: solid 1px #8F8FA2;
+  border-radius: 2px;
+  color: #3A3A47;
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1rem;
+  padding: calc(0.5rem - 1px) 0.5rem;
+  width: 100%;
+  -webkit-transition-property: box-shadow;
+  transition-property: box-shadow;
+  -webkit-transition-duration: .2s;
+  transition-duration: .2s;
+  border: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-decoration {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-cancel-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-decoration {
+  display: none;
+}
+
+.emotion-0:required {
+  box-shadow: none;
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:disabled {
+  border-color: #D3D4DD;
+  background-color: #F0F0F5;
+}
+
+.emotion-0:not(:disabled):hover {
+  border-color: #7A7B8E;
+}
+
+.emotion-0:not(:disabled):focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+}
+
+.emotion-0:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:focus {
+  box-shadow: none !important;
+}
+
+.emotion-11 {
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1.5rem;
+  color: #3A3A47;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  position: relative;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-transition: all .2s;
+  transition: all .2s;
+  font-weight: bold;
+  cursor: pointer;
+  background-color: transparent;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  color: #3A3A47;
+  -webkit-text-decoration: none;
+  text-decoration: none;
+  font-size: 0.875rem;
+  padding: calc(0.25rem - 1px) calc(0.5rem - 1px);
+  border-radius: inherit;
+}
+
+.emotion-11 > span {
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+}
+
+.emotion-11:not(:disabled):active {
+  box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
+}
+
+.emotion-11:focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #0069D0;
+}
+
+.emotion-11:not(:disabled):hover {
+  background-color: rgba(58,58,71,0.1);
+}
+
+.emotion-11:focus {
+  box-shadow: none;
+}
+
+.emotion-10 {
+  fill: currentColor;
+  font-size: 1.5rem;
+}
+
+<div>
+  <div>
+    <div
+      class="emotion-13"
+    >
+      <div
+        class="emotion-9"
+      >
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="startDate"
+                placeholder="mm/dd/yyyy"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+        <span
+          class="emotion-4"
+        >
+          <strong>
+            until
+          </strong>
+        </span>
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="finalDate"
+                placeholder="mm/dd/yyyy"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+      <span
+        class="emotion-12"
+      >
+        <button
+          class="emotion-11"
+          tabindex="-1"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-10"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M16 2c.619 0 .95.27.995.812l.005.13V4h1c1.273 0 1.938.607 1.996 1.822L20 6v14c0 1.273-.607 1.938-1.822 1.996L18 22H6c-1.273 0-1.938-.607-1.996-1.822L4 20V6.004c0-1.275.607-1.942 1.822-2L6 4h1V3c-.002-.667.33-1 1-1 .621 0 .954.287.998.862L9.004 3v1H15V2.941c0-.627.333-.941 1-.941zm2 8H6v10h12V10zm-8.998 6H10c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 18H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 16H10zM15 16c.667 0 1 .333 1 1s-.333 1-1 1h-1c-.667.001-1-.332-1-1 0-.668.335-1.001 1.002-1zm-5-4c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 14H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 12H10zm5 0c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L15 14h-1c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995l.138-.005H15zm3-6H6v2h12V6z"
+              />
+            </svg>
+          </span>
+        </button>
+      </span>
+    </div>
+  </div>
+</div>
+`;
+
+exports[`BaseRangeDateInput customization should allow ptBR placeholder customization via locale context 1`] = `
+.emotion-9 {
+  background-color: #FFFFFF;
+  border: 1px solid#AAAAB9;
+  border-radius: 2px;
+  cursor: default;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  position: relative;
+  padding-right: 2.5rem;
+  padding-left: 0.1rem;
+  -webkit-transition: box-shadow .2s ease;
+  transition: box-shadow .2s ease;
+}
+
+.emotion-9:required {
+  box-shadow: none;
+}
+
+.emotion-9:not(:disabled):hover {
+  border-color: #8F8FA2;
+}
+
+.emotion-9:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-9:focus-within:not(:disabled) {
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+  outline: none;
+}
+
+.emotion-4 {
+  cursor: default;
+  background: transparent;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+}
+
+.emotion-3 {
+  -webkit-flex: 1;
+  -ms-flex: 1;
+  flex: 1;
+}
+
+.emotion-13 {
+  position: relative;
+}
+
+.emotion-13 input {
+  padding-right: 3rem;
+}
+
+.emotion-12 {
+  position: absolute;
+  background-color: #F0F0F5;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  padding: 0.25rem;
+  width: 2.5rem;
+  top: 1px;
+  bottom: 1px;
+  right: 1px;
+}
+
+.emotion-1 {
+  position: relative;
+}
+
+.emotion-0 {
+  background-color: #FFFFFF;
+  border: solid 1px #8F8FA2;
+  border-radius: 2px;
+  color: #3A3A47;
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1rem;
+  padding: calc(0.5rem - 1px) 0.5rem;
+  width: 100%;
+  -webkit-transition-property: box-shadow;
+  transition-property: box-shadow;
+  -webkit-transition-duration: .2s;
+  transition-duration: .2s;
+  border: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-decoration {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-cancel-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-decoration {
+  display: none;
+}
+
+.emotion-0:required {
+  box-shadow: none;
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:disabled {
+  border-color: #D3D4DD;
+  background-color: #F0F0F5;
+}
+
+.emotion-0:not(:disabled):hover {
+  border-color: #7A7B8E;
+}
+
+.emotion-0:not(:disabled):focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+}
+
+.emotion-0:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:focus {
+  box-shadow: none !important;
+}
+
+.emotion-11 {
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1.5rem;
+  color: #3A3A47;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  position: relative;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-transition: all .2s;
+  transition: all .2s;
+  font-weight: bold;
+  cursor: pointer;
+  background-color: transparent;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  color: #3A3A47;
+  -webkit-text-decoration: none;
+  text-decoration: none;
+  font-size: 0.875rem;
+  padding: calc(0.25rem - 1px) calc(0.5rem - 1px);
+  border-radius: inherit;
+}
+
+.emotion-11 > span {
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+}
+
+.emotion-11:not(:disabled):active {
+  box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
+}
+
+.emotion-11:focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #0069D0;
+}
+
+.emotion-11:not(:disabled):hover {
+  background-color: rgba(58,58,71,0.1);
+}
+
+.emotion-11:focus {
+  box-shadow: none;
+}
+
+.emotion-10 {
+  fill: currentColor;
+  font-size: 1.5rem;
+}
+
+<div>
+  <div>
+    <div
+      class="emotion-13"
+    >
+      <div
+        class="emotion-9"
+      >
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="startDate"
+                placeholder="dd/mm/aaaa"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+        <span
+          class="emotion-4"
+        >
+          <strong>
+            até
+          </strong>
+        </span>
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="finalDate"
+                placeholder="dd/mm/aaaa"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+      <span
+        class="emotion-12"
+      >
+        <button
+          class="emotion-11"
+          tabindex="-1"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-10"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M16 2c.619 0 .95.27.995.812l.005.13V4h1c1.273 0 1.938.607 1.996 1.822L20 6v14c0 1.273-.607 1.938-1.822 1.996L18 22H6c-1.273 0-1.938-.607-1.996-1.822L4 20V6.004c0-1.275.607-1.942 1.822-2L6 4h1V3c-.002-.667.33-1 1-1 .621 0 .954.287.998.862L9.004 3v1H15V2.941c0-.627.333-.941 1-.941zm2 8H6v10h12V10zm-8.998 6H10c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 18H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 16H10zM15 16c.667 0 1 .333 1 1s-.333 1-1 1h-1c-.667.001-1-.332-1-1 0-.668.335-1.001 1.002-1zm-5-4c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 14H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 12H10zm5 0c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L15 14h-1c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995l.138-.005H15zm3-6H6v2h12V6z"
+              />
+            </svg>
+          </span>
+        </button>
+      </span>
+    </div>
+  </div>
+</div>
+`;
+
+exports[`BaseRangeDateInput customization should allow ptBr i18n in range separator 1`] = `
+.emotion-9 {
+  background-color: #FFFFFF;
+  border: 1px solid#AAAAB9;
+  border-radius: 2px;
+  cursor: default;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  position: relative;
+  padding-right: 2.5rem;
+  padding-left: 0.1rem;
+  -webkit-transition: box-shadow .2s ease;
+  transition: box-shadow .2s ease;
+}
+
+.emotion-9:required {
+  box-shadow: none;
+}
+
+.emotion-9:not(:disabled):hover {
+  border-color: #8F8FA2;
+}
+
+.emotion-9:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-9:focus-within:not(:disabled) {
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+  outline: none;
+}
+
+.emotion-4 {
+  cursor: default;
+  background: transparent;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+}
+
+.emotion-3 {
+  -webkit-flex: 1;
+  -ms-flex: 1;
+  flex: 1;
+}
+
+.emotion-13 {
+  position: relative;
+}
+
+.emotion-13 input {
+  padding-right: 3rem;
+}
+
+.emotion-12 {
+  position: absolute;
+  background-color: #F0F0F5;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  padding: 0.25rem;
+  width: 2.5rem;
+  top: 1px;
+  bottom: 1px;
+  right: 1px;
+}
+
+.emotion-1 {
+  position: relative;
+}
+
+.emotion-0 {
+  background-color: #FFFFFF;
+  border: solid 1px #8F8FA2;
+  border-radius: 2px;
+  color: #3A3A47;
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1rem;
+  padding: calc(0.5rem - 1px) 0.5rem;
+  width: 100%;
+  -webkit-transition-property: box-shadow;
+  transition-property: box-shadow;
+  -webkit-transition-duration: .2s;
+  transition-duration: .2s;
+  border: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-decoration {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-cancel-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-decoration {
+  display: none;
+}
+
+.emotion-0:required {
+  box-shadow: none;
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:disabled {
+  border-color: #D3D4DD;
+  background-color: #F0F0F5;
+}
+
+.emotion-0:not(:disabled):hover {
+  border-color: #7A7B8E;
+}
+
+.emotion-0:not(:disabled):focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+}
+
+.emotion-0:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:focus {
+  box-shadow: none !important;
+}
+
+.emotion-11 {
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1.5rem;
+  color: #3A3A47;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  position: relative;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-transition: all .2s;
+  transition: all .2s;
+  font-weight: bold;
+  cursor: pointer;
+  background-color: transparent;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  color: #3A3A47;
+  -webkit-text-decoration: none;
+  text-decoration: none;
+  font-size: 0.875rem;
+  padding: calc(0.25rem - 1px) calc(0.5rem - 1px);
+  border-radius: inherit;
+}
+
+.emotion-11 > span {
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+}
+
+.emotion-11:not(:disabled):active {
+  box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
+}
+
+.emotion-11:focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #0069D0;
+}
+
+.emotion-11:not(:disabled):hover {
+  background-color: rgba(58,58,71,0.1);
+}
+
+.emotion-11:focus {
+  box-shadow: none;
+}
+
+.emotion-10 {
+  fill: currentColor;
+  font-size: 1.5rem;
+}
+
+<div>
+  <div>
+    <div
+      class="emotion-13"
+    >
+      <div
+        class="emotion-9"
+      >
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="startDate"
+                placeholder="dd/mm/aaaa"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+        <span
+          class="emotion-4"
+        >
+          <strong>
+            até
+          </strong>
+        </span>
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="finalDate"
+                placeholder="dd/mm/aaaa"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+      <span
+        class="emotion-12"
+      >
+        <button
+          class="emotion-11"
+          tabindex="-1"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-10"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M16 2c.619 0 .95.27.995.812l.005.13V4h1c1.273 0 1.938.607 1.996 1.822L20 6v14c0 1.273-.607 1.938-1.822 1.996L18 22H6c-1.273 0-1.938-.607-1.996-1.822L4 20V6.004c0-1.275.607-1.942 1.822-2L6 4h1V3c-.002-.667.33-1 1-1 .621 0 .954.287.998.862L9.004 3v1H15V2.941c0-.627.333-.941 1-.941zm2 8H6v10h12V10zm-8.998 6H10c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 18H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 16H10zM15 16c.667 0 1 .333 1 1s-.333 1-1 1h-1c-.667.001-1-.332-1-1 0-.668.335-1.001 1.002-1zm-5-4c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 14H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 12H10zm5 0c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L15 14h-1c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995l.138-.005H15zm3-6H6v2h12V6z"
+              />
+            </svg>
+          </span>
+        </button>
+      </span>
+    </div>
+  </div>
+</div>
+`;
+
+exports[`BaseRangeDateInput render should render correctly 1`] = `
+.emotion-9 {
+  background-color: #FFFFFF;
+  border: 1px solid#AAAAB9;
+  border-radius: 2px;
+  cursor: default;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  position: relative;
+  padding-right: 2.5rem;
+  padding-left: 0.1rem;
+  -webkit-transition: box-shadow .2s ease;
+  transition: box-shadow .2s ease;
+}
+
+.emotion-9:required {
+  box-shadow: none;
+}
+
+.emotion-9:not(:disabled):hover {
+  border-color: #8F8FA2;
+}
+
+.emotion-9:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-9:focus-within:not(:disabled) {
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+  outline: none;
+}
+
+.emotion-4 {
+  cursor: default;
+  background: transparent;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+}
+
+.emotion-3 {
+  -webkit-flex: 1;
+  -ms-flex: 1;
+  flex: 1;
+}
+
+.emotion-13 {
+  position: relative;
+}
+
+.emotion-13 input {
+  padding-right: 3rem;
+}
+
+.emotion-12 {
+  position: absolute;
+  background-color: #F0F0F5;
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  padding: 0.25rem;
+  width: 2.5rem;
+  top: 1px;
+  bottom: 1px;
+  right: 1px;
+}
+
+.emotion-1 {
+  position: relative;
+}
+
+.emotion-0 {
+  background-color: #FFFFFF;
+  border: solid 1px #8F8FA2;
+  border-radius: 2px;
+  color: #3A3A47;
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1rem;
+  padding: calc(0.5rem - 1px) 0.5rem;
+  width: 100%;
+  -webkit-transition-property: box-shadow;
+  transition-property: box-shadow;
+  -webkit-transition-duration: .2s;
+  transition-duration: .2s;
+  border: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-decoration {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-cancel-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-button {
+  display: none;
+}
+
+.emotion-0[type="search"]::-webkit-search-results-decoration {
+  display: none;
+}
+
+.emotion-0:required {
+  box-shadow: none;
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:disabled {
+  border-color: #D3D4DD;
+  background-color: #F0F0F5;
+}
+
+.emotion-0:not(:disabled):hover {
+  border-color: #7A7B8E;
+}
+
+.emotion-0:not(:disabled):focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
+}
+
+.emotion-0:not(:disabled):active {
+  border-color: #0069D0;
+  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.09);
+}
+
+.emotion-0::-webkit-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::-moz-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:-ms-input-placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0::placeholder {
+  color: #AAAAB9;
+}
+
+.emotion-0:focus {
+  box-shadow: none !important;
+}
+
+.emotion-11 {
+  font-family: "IBM Plex Sans",sans-serif;
+  font-size: 0.8125rem;
+  line-height: 1.5rem;
+  color: #3A3A47;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  position: relative;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  -webkit-transition: all .2s;
+  transition: all .2s;
+  font-weight: bold;
+  cursor: pointer;
+  background-color: transparent;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  color: #3A3A47;
+  -webkit-text-decoration: none;
+  text-decoration: none;
+  font-size: 0.875rem;
+  padding: calc(0.25rem - 1px) calc(0.5rem - 1px);
+  border-radius: inherit;
+}
+
+.emotion-11 > span {
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+}
+
+.emotion-11:not(:disabled):active {
+  box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
+}
+
+.emotion-11:focus {
+  outline: none;
+  box-shadow: 0 0 0 2px #0069D0;
+}
+
+.emotion-11:not(:disabled):hover {
+  background-color: rgba(58,58,71,0.1);
+}
+
+.emotion-11:focus {
+  box-shadow: none;
+}
+
+.emotion-10 {
+  fill: currentColor;
+  font-size: 1.5rem;
+}
+
+<div>
+  <div>
+    <div
+      class="emotion-13"
+    >
+      <div
+        class="emotion-9"
+      >
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="startDate"
+                placeholder="mm/dd/yyyy"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+        <span
+          class="emotion-4"
+        >
+          <strong>
+            until
+          </strong>
+        </span>
+        <div
+          class="emotion-3"
+        >
+          <div
+            class="emotion-2"
+          >
+            <div
+              class="emotion-1"
+            >
+              <input
+                autocomplete="off"
+                class="emotion-0"
+                name="finalDate"
+                placeholder="mm/dd/yyyy"
+                type="text"
+                value=""
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+      <span
+        class="emotion-12"
+      >
+        <button
+          class="emotion-11"
+          tabindex="-1"
+          type="button"
+        >
+          <span>
+            <svg
+              aria-hidden="true"
+              class="emotion-10"
+              height="1em"
+              role="img"
+              viewBox="0 0 24 24"
+              width="1em"
+            >
+              <path
+                d="M16 2c.619 0 .95.27.995.812l.005.13V4h1c1.273 0 1.938.607 1.996 1.822L20 6v14c0 1.273-.607 1.938-1.822 1.996L18 22H6c-1.273 0-1.938-.607-1.996-1.822L4 20V6.004c0-1.275.607-1.942 1.822-2L6 4h1V3c-.002-.667.33-1 1-1 .621 0 .954.287.998.862L9.004 3v1H15V2.941c0-.627.333-.941 1-.941zm2 8H6v10h12V10zm-8.998 6H10c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 18H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 16H10zM15 16c.667 0 1 .333 1 1s-.333 1-1 1h-1c-.667.001-1-.332-1-1 0-.668.335-1.001 1.002-1zm-5-4c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L10 14H9c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995L9.002 12H10zm5 0c.667 0 1 .333 1 1 0 .619-.287.95-.862.995L15 14h-1c-.667.001-1-.332-1-1 0-.62.289-.952.864-.995l.138-.005H15zm3-6H6v2h12V6z"
+              />
+            </svg>
+          </span>
+        </button>
+      </span>
+    </div>
+  </div>
+</div>
+`;
+
+exports[`BaseRangeDateInput render should render correctly when disabled 1`] = `
 .emotion-3 {
   -webkit-flex: 1;
   -ms-flex: 1;
@@ -600,6 +1926,7 @@ exports[`PeriodInput render should render correctly when disabled 1`] = `
                 autocomplete="off"
                 class="emotion-0"
                 disabled=""
+                name="startDate"
                 placeholder="mm/dd/yyyy"
                 type="text"
                 value=""
@@ -627,6 +1954,7 @@ exports[`PeriodInput render should render correctly when disabled 1`] = `
                 autocomplete="off"
                 class="emotion-0"
                 disabled=""
+                name="finalDate"
                 placeholder="mm/dd/yyyy"
                 type="text"
                 value=""
@@ -665,7 +1993,7 @@ exports[`PeriodInput render should render correctly when disabled 1`] = `
 </div>
 `;
 
-exports[`PeriodInput render should render correctly when invalid 1`] = `
+exports[`BaseRangeDateInput render should render correctly when invalid 1`] = `
 .emotion-4 {
   cursor: default;
   background: transparent;
@@ -943,6 +2271,7 @@ exports[`PeriodInput render should render correctly when invalid 1`] = `
               <input
                 autocomplete="off"
                 class="emotion-0"
+                name="startDate"
                 placeholder="mm/dd/yyyy"
                 type="text"
                 value=""
@@ -969,6 +2298,7 @@ exports[`PeriodInput render should render correctly when invalid 1`] = `
               <input
                 autocomplete="off"
                 class="emotion-0"
+                name="finalDate"
                 placeholder="mm/dd/yyyy"
                 type="text"
                 value=""
diff --git a/src/components/RangeDateField/__snapshots__/RangeDateField.test.tsx.snap b/src/components/RangeDateField/__snapshots__/RangeDateField.test.tsx.snap
index 717ef5171..54dc7664b 100644
--- a/src/components/RangeDateField/__snapshots__/RangeDateField.test.tsx.snap
+++ b/src/components/RangeDateField/__snapshots__/RangeDateField.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`PeriodField render should render correctly 1`] = `
+exports[`RangeDateField render should render correctly 1`] = `
 .emotion-9 {
   background-color: #FFFFFF;
   border: 1px solid#AAAAB9;
@@ -270,6 +270,7 @@ exports[`PeriodField render should render correctly 1`] = `
                   <input
                     autocomplete="off"
                     class="emotion-0"
+                    name="startDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -296,6 +297,7 @@ exports[`PeriodField render should render correctly 1`] = `
                   <input
                     autocomplete="off"
                     class="emotion-0"
+                    name="finalDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -335,7 +337,7 @@ exports[`PeriodField render should render correctly 1`] = `
 </div>
 `;
 
-exports[`PeriodField render should render correctly when disabled 1`] = `
+exports[`RangeDateField render should render correctly when disabled 1`] = `
 .emotion-3 {
   -webkit-flex: 1;
   -ms-flex: 1;
@@ -610,6 +612,7 @@ exports[`PeriodField render should render correctly when disabled 1`] = `
                     autocomplete="off"
                     class="emotion-0"
                     disabled=""
+                    name="startDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -637,6 +640,7 @@ exports[`PeriodField render should render correctly when disabled 1`] = `
                     autocomplete="off"
                     class="emotion-0"
                     disabled=""
+                    name="finalDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -677,7 +681,7 @@ exports[`PeriodField render should render correctly when disabled 1`] = `
 </div>
 `;
 
-exports[`PeriodField render should render correctly when invalid 1`] = `
+exports[`RangeDateField render should render correctly when invalid 1`] = `
 .emotion-4 {
   cursor: default;
   background: transparent;
@@ -959,6 +963,7 @@ exports[`PeriodField render should render correctly when invalid 1`] = `
                   <input
                     autocomplete="off"
                     class="emotion-0"
+                    name="startDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -985,6 +990,7 @@ exports[`PeriodField render should render correctly when invalid 1`] = `
                   <input
                     autocomplete="off"
                     class="emotion-0"
+                    name="finalDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -1024,7 +1030,7 @@ exports[`PeriodField render should render correctly when invalid 1`] = `
 </div>
 `;
 
-exports[`PeriodField render should render correctly when opened 1`] = `
+exports[`RangeDateField render should render correctly when opened 1`] = `
 .emotion-9 {
   background-color: #FFFFFF;
   border: 1px solid#AAAAB9;
@@ -1428,8 +1434,8 @@ exports[`PeriodField render should render correctly when opened 1`] = `
                 >
                   <input
                     autocomplete="off"
-                    calendarprops="[object Object]"
                     class="emotion-0"
+                    name="startDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -1455,8 +1461,8 @@ exports[`PeriodField render should render correctly when opened 1`] = `
                 >
                   <input
                     autocomplete="off"
-                    calendarprops="[object Object]"
                     class="emotion-0"
+                    name="finalDate"
                     placeholder="mm/dd/yyyy"
                     type="text"
                     value=""
@@ -2028,3 +2034,153 @@ exports[`PeriodField render should render correctly when opened 1`] = `
   </div>
 </div>
 `;
+
+exports[`RangeDateField render should show calendar correctly when inputs are cleaned 1`] = `
+.emotion-0 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+}
+
+.emotion-0:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+<span
+  aria-selected="false"
+  class="emotion-0"
+  role="button"
+>
+  01
+</span>
+`;
+
+exports[`RangeDateField render should show calendar correctly when only finalDate is defined and is focused 1`] = `
+.emotion-0 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+  background: #0069D0;
+  color: #FFFFFF;
+  font-weight: bold;
+}
+
+.emotion-0:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+.emotion-0:hover {
+  background: #0069D0;
+  color: #FFFFFF;
+}
+
+<span
+  aria-selected="true"
+  class="emotion-0"
+  role="button"
+>
+  01
+</span>
+`;
+
+exports[`RangeDateField render should show calendar correctly when only finalDate is defined and is focused 2`] = `"received is not a function"`;
+
+exports[`RangeDateField render should show calendar correctly when only startDate is defined and is focused 1`] = `
+.emotion-0 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+  background: #0069D0;
+  color: #FFFFFF;
+  font-weight: bold;
+}
+
+.emotion-0:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+.emotion-0:hover {
+  background: #0069D0;
+  color: #FFFFFF;
+}
+
+<span
+  aria-selected="true"
+  class="emotion-0"
+  role="button"
+>
+  01
+</span>
+`;
+
+exports[`RangeDateField render should show calendar correctly when only startDate is defined and is focused 2`] = `"received is not a function"`;
+
+exports[`RangeDateField render should show calendar correctly when startDate and finalDate are defined and finalDate is focused 1`] = `"received is not a function"`;
+
+exports[`RangeDateField render should show calendar correctly when startDate and finalDate are defined and finalDate is focused 2`] = `
+.emotion-0 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+  background: #0069D0;
+  color: #FFFFFF;
+  font-weight: bold;
+}
+
+.emotion-0:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+.emotion-0:hover {
+  background: #0069D0;
+  color: #FFFFFF;
+}
+
+<span
+  aria-selected="true"
+  class="emotion-0"
+  role="button"
+>
+  15
+</span>
+`;
+
+exports[`RangeDateField render should show calendar correctly when startDate and finalDate are defined and startDate is focused 1`] = `
+.emotion-0 {
+  width: 2rem;
+  padding: 0.25rem 0;
+  display: inline-block;
+  border-radius: 50%;
+  background: #0069D0;
+  color: #FFFFFF;
+  font-weight: bold;
+}
+
+.emotion-0:hover {
+  cursor: pointer;
+  background: #F0F0F5;
+}
+
+.emotion-0:hover {
+  background: #0069D0;
+  color: #FFFFFF;
+}
+
+<span
+  aria-selected="true"
+  class="emotion-0"
+  role="button"
+>
+  01
+</span>
+`;
+
+exports[`RangeDateField render should show calendar correctly when startDate and finalDate are defined and startDate is focused 2`] = `"received is not a function"`;