diff --git a/README.md b/README.md
index 2592a32..94067b4 100644
--- a/README.md
+++ b/README.md
@@ -102,9 +102,11 @@ Example if `fixedDecimalLength` was 2:
 | id                 | `string`   |         | Component id                                                             |
 | maxLength          | `number`   |         | Maximum characters the user can enter                                    |
 | onChange           | `function` |         | Handle change in value                                                   |
+| onBlurValue        | `function` |         | Handle value onBlur                                                      |
 | placeholder        | `string`   |         | Placeholder if no value                                                  |
 | precision          | `number`   |         | Specify decimal precision for padding/trimming                           |
 | prefix             | `string`   |         | Include a prefix eg. £ or \$                                             |
+| step               | `number`   |         | Incremental value change on arrow down and arrow up key press            |
 | decimalSeparator   | `string`   | `.`     | Separator between integer part and fractional part of value              |
 | groupSeparator     | `string`   | `,`     | Separator between thousand, million and billion                          |
 | turnOffSeparators  | `boolean`  | `false` | Disable auto adding the group separator between values, eg. 1000 > 1,000 |
diff --git a/src/components/CurrencyInput.tsx b/src/components/CurrencyInput.tsx
index 1cebb57..5ba8ec2 100644
--- a/src/components/CurrencyInput.tsx
+++ b/src/components/CurrencyInput.tsx
@@ -12,13 +12,14 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
   defaultValue,
   disabled = false,
   maxLength: userMaxLength,
-  value,
+  value: userValue,
   onChange,
   onBlurValue,
   fixedDecimalLength,
   placeholder,
   precision,
   prefix,
+  step,
   decimalSeparator = '.',
   groupSeparator = ',',
   turnOffSeparators = false,
@@ -62,10 +63,8 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
 
   const onFocus = (): number => (stateValue ? stateValue.length : 0);
 
-  const processChange = ({
-    target: { value, selectionStart },
-  }: React.ChangeEvent<HTMLInputElement>): void => {
-    const valueOnly = cleanValue({ value: String(value), ...cleanValueOptions });
+  const processChange = (value: string, selectionStart?: number | null): void => {
+    const valueOnly = cleanValue({ value, ...cleanValueOptions });
 
     if (!valueOnly) {
       onChange && onChange(undefined, name);
@@ -73,7 +72,7 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
       return;
     }
 
-    if (userMaxLength && valueOnly.length > userMaxLength) {
+    if (userMaxLength && valueOnly.replace(/-/g, '').length > userMaxLength) {
       return;
     }
 
@@ -86,7 +85,7 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
     const formattedValue = formatValue({ value: valueOnly, ...formatValueOptions });
 
     /* istanbul ignore next */
-    if (selectionStart) {
+    if (selectionStart !== undefined && selectionStart !== null) {
       const cursor = selectionStart + (formattedValue.length - value.length) || 1;
       setCursor(cursor);
     }
@@ -96,6 +95,12 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
     onChange && onChange(valueOnly, name);
   };
 
+  const handleOnChange = ({
+    target: { value, selectionStart },
+  }: React.ChangeEvent<HTMLInputElement>): void => {
+    processChange(value, selectionStart);
+  };
+
   const handleOnBlur = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>): void => {
     const valueOnly = cleanValue({ value, ...cleanValueOptions });
 
@@ -116,6 +121,23 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
     setStateValue(formattedValue);
   };
 
+  const handleOnKeyDown = ({ key }: React.KeyboardEvent<HTMLInputElement>) => {
+    if (step && (key === 'ArrowUp' || key === 'ArrowDown')) {
+      const currentValue =
+        Number(
+          userValue !== undefined
+            ? userValue
+            : cleanValue({ value: stateValue, ...cleanValueOptions })
+        ) || 0;
+      const newValue =
+        key === 'ArrowUp'
+          ? String(currentValue + Number(step))
+          : String(currentValue - Number(step));
+
+      processChange(newValue);
+    }
+  };
+
   /* istanbul ignore next */
   useEffect(() => {
     if (inputRef && inputRef.current) {
@@ -124,7 +146,9 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
   }, [cursor, inputRef]);
 
   const formattedPropsValue =
-    value !== undefined ? formatValue({ value: String(value), ...formatValueOptions }) : undefined;
+    userValue !== undefined
+      ? formatValue({ value: String(userValue), ...formatValueOptions })
+      : undefined;
 
   return (
     <input
@@ -133,9 +157,10 @@ export const CurrencyInput: FC<CurrencyInputProps> = ({
       id={id}
       name={name}
       className={className}
-      onChange={processChange}
+      onChange={handleOnChange}
       onBlur={handleOnBlur}
       onFocus={onFocus}
+      onKeyDown={handleOnKeyDown}
       placeholder={placeholder}
       disabled={disabled}
       value={
diff --git a/src/components/CurrencyInputProps.ts b/src/components/CurrencyInputProps.ts
index 07d9740..0629932 100644
--- a/src/components/CurrencyInputProps.ts
+++ b/src/components/CurrencyInputProps.ts
@@ -84,6 +84,11 @@ export type CurrencyInputProps = Overwrite<
      */
     prefix?: string;
 
+    /**
+     * Incremental value change on arrow down and arrow up key press
+     */
+    step?: number;
+
     /**
      * Separator between integer part and fractional part of value. Cannot be a number
      *
diff --git a/src/components/__tests__/CurrencyInput-handleKeyDown.spec.tsx b/src/components/__tests__/CurrencyInput-handleKeyDown.spec.tsx
new file mode 100644
index 0000000..e26fe1b
--- /dev/null
+++ b/src/components/__tests__/CurrencyInput-handleKeyDown.spec.tsx
@@ -0,0 +1,155 @@
+import { shallow } from 'enzyme';
+import React from 'react';
+import CurrencyInput from '../CurrencyInput';
+
+const id = 'validationCustom01';
+
+describe('<CurrencyInput /> component > handleKeyDown', () => {
+  const onChangeSpy = jest.fn();
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('should not change value if no step prop', () => {
+    const view = shallow(
+      <CurrencyInput id={id} prefix="£" defaultValue={100} onChange={onChangeSpy} />
+    );
+
+    // Arrow up
+    view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+    expect(onChangeSpy).not.toBeCalled();
+    expect(view.update().find(`#${id}`).prop('value')).toBe('£100');
+
+    // Arrow down
+    view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+    expect(onChangeSpy).not.toBeCalled();
+    expect(view.update().find(`#${id}`).prop('value')).toBe('£100');
+  });
+
+  it('should handle negative step', () => {
+    const view = shallow(
+      <CurrencyInput id={id} prefix="£" defaultValue={100} step={-2} onChange={onChangeSpy} />
+    );
+
+    view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+    expect(onChangeSpy).toHaveBeenCalledWith('98', undefined);
+    expect(view.update().find(`#${id}`).prop('value')).toBe('£98');
+
+    view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+    expect(onChangeSpy).toHaveBeenCalledWith('100', undefined);
+    expect(view.update().find(`#${id}`).prop('value')).toBe('£100');
+  });
+
+  describe('without value ie. default 0', () => {
+    it('should handle arrow down key', () => {
+      const view = shallow(<CurrencyInput id={id} prefix="£" step={1} onChange={onChangeSpy} />);
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+      expect(onChangeSpy).toBeCalledWith('-1', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('-£1');
+    });
+
+    it('should handle arrow down key', () => {
+      const view = shallow(<CurrencyInput id={id} prefix="£" step={1} onChange={onChangeSpy} />);
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+      expect(onChangeSpy).toBeCalledWith('1', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£1');
+    });
+  });
+
+  describe('with value 99 and step 1.25', () => {
+    it('should handle arrow down key', () => {
+      const view = shallow(
+        <CurrencyInput id={id} prefix="£" value={99} step={1.25} onChange={onChangeSpy} />
+      );
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+      expect(onChangeSpy).toHaveBeenCalledWith('97.75', undefined);
+    });
+
+    it('should handle arrow up key', () => {
+      const view = shallow(
+        <CurrencyInput id={id} prefix="£" value={99} step={1.25} onChange={onChangeSpy} />
+      );
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+      expect(onChangeSpy).toHaveBeenCalledWith('100.25', undefined);
+    });
+  });
+
+  describe('with defaultValue 100 and step 5.5', () => {
+    it('should handle arrow down key', () => {
+      const view = shallow(
+        <CurrencyInput id={id} prefix="£" defaultValue={100} step={5.5} onChange={onChangeSpy} />
+      );
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+      expect(onChangeSpy).toBeCalledWith('94.5', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£94.5');
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+      expect(onChangeSpy).toBeCalledWith('89', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£89');
+    });
+
+    it('should handle arrow up key', () => {
+      const view = shallow(
+        <CurrencyInput id={id} prefix="£" defaultValue={100} step={5.5} onChange={onChangeSpy} />
+      );
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+      expect(onChangeSpy).toBeCalledWith('105.5', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£105.5');
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+      expect(onChangeSpy).toBeCalledWith('111', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£111');
+    });
+  });
+
+  describe('with max length 2', () => {
+    it('should handle negative value', () => {
+      const view = shallow(
+        <CurrencyInput
+          id={id}
+          prefix="£"
+          defaultValue={-99}
+          step={1}
+          maxLength={2}
+          onChange={onChangeSpy}
+        />
+      );
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+      expect(onChangeSpy).not.toBeCalled();
+      expect(view.update().find(`#${id}`).prop('value')).toBe('-£99');
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+      expect(onChangeSpy).toHaveBeenCalledWith('-98', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('-£98');
+    });
+
+    it('should handle positive value', () => {
+      const view = shallow(
+        <CurrencyInput
+          id={id}
+          prefix="£"
+          defaultValue={99}
+          step={1}
+          maxLength={2}
+          onChange={onChangeSpy}
+        />
+      );
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowUp' });
+      expect(onChangeSpy).not.toBeCalled();
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£99');
+
+      view.find(`#${id}`).simulate('keyDown', { key: 'ArrowDown' });
+      expect(onChangeSpy).toHaveBeenCalledWith('98', undefined);
+      expect(view.update().find(`#${id}`).prop('value')).toBe('£98');
+    });
+  });
+});
diff --git a/src/components/__tests__/CurrencyInput-maxLength.spec.tsx b/src/components/__tests__/CurrencyInput-maxLength.spec.tsx
new file mode 100644
index 0000000..553263b
--- /dev/null
+++ b/src/components/__tests__/CurrencyInput-maxLength.spec.tsx
@@ -0,0 +1,59 @@
+import { shallow } from 'enzyme';
+import React from 'react';
+import CurrencyInput from '../CurrencyInput';
+
+const id = 'validationCustom01';
+
+describe('<CurrencyInput /> component > maxLength', () => {
+  const onChangeSpy = jest.fn();
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('should not allow more values than max length', () => {
+    const view = shallow(
+      <CurrencyInput
+        id={id}
+        name={name}
+        prefix="£"
+        onChange={onChangeSpy}
+        maxLength={3}
+        defaultValue={123}
+      />
+    );
+
+    const input = view.find(`#${id}`);
+    expect(input.prop('value')).toBe('£123');
+
+    input.simulate('change', { target: { value: '£1234' } });
+    expect(onChangeSpy).not.toBeCalled();
+
+    const updatedView = view.update();
+    expect(updatedView.find(`#${id}`).prop('value')).toBe('£123');
+  });
+
+  it('should apply max length rule to negative value', () => {
+    const view = shallow(
+      <CurrencyInput
+        id={id}
+        name={name}
+        prefix="£"
+        onChange={onChangeSpy}
+        maxLength={3}
+        defaultValue={-123}
+      />
+    );
+
+    const input = view.find(`#${id}`);
+    expect(input.prop('value')).toBe('-£123');
+
+    input.simulate('change', { target: { value: '-£1234' } });
+    expect(onChangeSpy).not.toBeCalled();
+    expect(view.update().find(`#${id}`).prop('value')).toBe('-£123');
+
+    input.simulate('change', { target: { value: '-£125' } });
+    expect(onChangeSpy).toHaveBeenCalledWith('-125', '');
+    expect(view.update().find(`#${id}`).prop('value')).toBe('-£125');
+  });
+});
diff --git a/src/components/__tests__/CurrencyInput.spec.tsx b/src/components/__tests__/CurrencyInput.spec.tsx
index 8e05673..e6fc30d 100644
--- a/src/components/__tests__/CurrencyInput.spec.tsx
+++ b/src/components/__tests__/CurrencyInput.spec.tsx
@@ -48,14 +48,19 @@ describe('<CurrencyInput /> component', () => {
   });
 
   it('Renders with value prop', () => {
-    const value = 49.99;
-
-    const view = shallow(<CurrencyInput id={id} value={value} className={className} prefix="£" />);
+    const view = shallow(<CurrencyInput id={id} value={49.99} className={className} prefix="£" />);
     const input = view.find(`#${id}`);
 
     expect(input.prop('value')).toBe('£49.99');
   });
 
+  it('Renders with value 0', () => {
+    const view = shallow(<CurrencyInput id={id} value={0} className={className} prefix="£" />);
+    const input = view.find(`#${id}`);
+
+    expect(input.prop('value')).toBe('£0');
+  });
+
   it('should go to end of string on focus', () => {
     const view = shallow(<CurrencyInput id={id} defaultValue={123} />);
     view.find(`#${id}`).simulate('focus');
@@ -88,7 +93,7 @@ describe('<CurrencyInput /> component', () => {
 
   it('should allow 0 value on change', () => {
     const view = shallow(<CurrencyInput id={id} name={name} prefix="£" onChange={onChangeSpy} />);
-    view.find(`#${id}`).simulate('change', { target: { value: 0 } });
+    view.find(`#${id}`).simulate('change', { target: { value: '0' } });
     expect(onChangeSpy).toBeCalledWith('0', name);
 
     const updatedView = view.update();
@@ -127,28 +132,4 @@ describe('<CurrencyInput /> component', () => {
     const updatedView = view.update();
     expect(updatedView.find(`#${id}`).prop('value')).toBe('£123');
   });
-
-  describe('maxLength', () => {
-    it('should not allow more values than max length', () => {
-      const view = shallow(
-        <CurrencyInput
-          id={id}
-          name={name}
-          prefix="£"
-          onChange={onChangeSpy}
-          maxLength={3}
-          defaultValue={123}
-        />
-      );
-
-      const input = view.find(`#${id}`);
-      expect(input.prop('value')).toBe('£123');
-
-      input.simulate('change', { target: { value: '£1234' } });
-      expect(onChangeSpy).not.toBeCalled();
-
-      const updatedView = view.update();
-      expect(updatedView.find(`#${id}`).prop('value')).toBe('£123');
-    });
-  });
 });
diff --git a/src/examples/Example1.tsx b/src/examples/Example1.tsx
index b58ea4a..e50acab 100644
--- a/src/examples/Example1.tsx
+++ b/src/examples/Example1.tsx
@@ -73,6 +73,7 @@ export const Example1: FC = () => {
                 onBlurValue={handleOnBlurValue}
                 prefix={prefix}
                 precision={2}
+                step={1}
               />
               <div className="invalid-feedback">{errorMessage}</div>
             </div>
diff --git a/src/examples/Example2.tsx b/src/examples/Example2.tsx
index 3f1c24e..3827c52 100644
--- a/src/examples/Example2.tsx
+++ b/src/examples/Example2.tsx
@@ -51,6 +51,7 @@ export const Example2: FC = () => {
                 onChange={validateValue}
                 onBlurValue={handleOnBlurValue}
                 prefix={'$'}
+                step={10}
               />
               <div className="invalid-feedback">{errorMessage}</div>
             </div>
diff --git a/src/examples/FormatValuesExample.tsx b/src/examples/FormatValuesExample.tsx
index ef67bfb..6810435 100644
--- a/src/examples/FormatValuesExample.tsx
+++ b/src/examples/FormatValuesExample.tsx
@@ -2,7 +2,7 @@ import React, { FC, useState } from 'react';
 import { formatValue } from '../components/utils';
 
 const FormatValuesExample: FC = () => {
-  const [value, setValue] = useState('123456789.999999');
+  const [value, setValue] = useState('123456789.999');
   const [prefix, setPrefix] = useState('$');
   const [groupSeparator, setGroupSeparator] = useState(',');
   const [decimalSeparator, setDecimalSeparator] = useState('.');
@@ -115,7 +115,7 @@ const FormatValuesExample: FC = () => {
           </div>
           <div className="mt-5">
             Formatted value:
-            <div className="display-2">
+            <div className="display-4">
               {formatValue({
                 value,
                 groupSeparator,