diff --git a/packages/react-forms/src/InputRadio/InputRadio.md b/packages/react-forms/src/InputRadio/InputRadio.md
new file mode 100644
index 00000000..5444f35c
--- /dev/null
+++ b/packages/react-forms/src/InputRadio/InputRadio.md
@@ -0,0 +1,34 @@
+The `InputRadio` component provides an API compatible with the [`input[type=radio]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio) HTML element.
+
+```js
+
+```
diff --git a/packages/react-forms/src/InputRadio/__snapshots__/index.test.js.snap b/packages/react-forms/src/InputRadio/__snapshots__/index.test.js.snap
new file mode 100644
index 00000000..4b7d7266
--- /dev/null
+++ b/packages/react-forms/src/InputRadio/__snapshots__/index.test.js.snap
@@ -0,0 +1,130 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders a disabled InputRadio 1`] = `
+.emotion-0 {
+ opacity: 0;
+ position: absolute;
+ width: 0;
+ height: 0;
+ pointer-events: none;
+}
+
+.emotion-3 {
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #8F9BA3;
+ margin: 1px;
+ -webkit-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
+ opacity: 0.4;
+}
+
+.emotion-1:checked ~ .emotion-3 {
+ border-width: 5px;
+ border-color: #00c1bb;
+}
+
+.emotion-1:focus-visible ~ .emotion-3 {
+ box-shadow: 0 0 0 0.5px #FFFFFF,0 0 2px 2px rgba(0,193,187,0.8);
+}
+
+.emotion-1:focus-visible ~ .emotion-3:hover {
+ box-shadow: 0 0 0 0.5px #FFFFFF,0 0 2px 2px rgba(0,193,187,0.8),0 0 4px rgba(27,31,34,0.8);
+}
+
+.emotion-3:hover {
+ box-shadow: 0 0 4px rgba(27,31,34,0.8);
+}
+
+.emotion-3:hover {
+ box-shadow: none;
+}
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`renders an InputRadio 1`] = `
+.emotion-0 {
+ opacity: 0;
+ position: absolute;
+ width: 0;
+ height: 0;
+ pointer-events: none;
+}
+
+.emotion-3 {
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #8F9BA3;
+ margin: 1px;
+ -webkit-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
+}
+
+.emotion-1:checked ~ .emotion-3 {
+ border-width: 5px;
+ border-color: #00c1bb;
+}
+
+.emotion-1:focus-visible ~ .emotion-3 {
+ box-shadow: 0 0 0 0.5px #FFFFFF,0 0 2px 2px rgba(0,193,187,0.8);
+}
+
+.emotion-1:focus-visible ~ .emotion-3:hover {
+ box-shadow: 0 0 0 0.5px #FFFFFF,0 0 2px 2px rgba(0,193,187,0.8),0 0 4px rgba(27,31,34,0.8);
+}
+
+.emotion-3:hover {
+ box-shadow: 0 0 4px rgba(27,31,34,0.8);
+}
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/packages/react-forms/src/InputRadio/index.js b/packages/react-forms/src/InputRadio/index.js
new file mode 100644
index 00000000..590c3aad
--- /dev/null
+++ b/packages/react-forms/src/InputRadio/index.js
@@ -0,0 +1,85 @@
+// @flow
+import * as React from 'react';
+import styled from '@emotion/styled/macro';
+import css from '@emotion/css/macro';
+import { withFallback as wf } from '@quid/theme';
+import Color from 'color';
+import { INPUT_ATTRIBUTES, omit, include } from '../utils/inputPropsFilters';
+
+export const RING_SIZE = 5;
+export const WIDTH = 8 + RING_SIZE * 2;
+export const HEIGHT = 8 + RING_SIZE * 2;
+const OUTLINE_ON = wf(props =>
+ Color(props.theme.colors.selected)
+ .alpha(0.8)
+ .string()
+);
+const OUTLINE_HOVER = wf(props =>
+ Color(
+ props.theme.current === 'light'
+ ? props.theme.colors.gray7
+ : props.theme.colors.gray2
+ )
+ .alpha(0.8)
+ .string()
+);
+
+const Input = styled.input`
+ opacity: 0;
+ position: absolute;
+ width: 0;
+ height: 0;
+ pointer-events: none;
+`;
+
+const Circle = styled.div`
+ width: ${WIDTH}px;
+ height: ${HEIGHT}px;
+ border-radius: 50%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: ${wf(props => props.theme.colors.gray3)};
+ margin: 1px;
+ transition: all 0.2s ease-in-out;
+
+ ${Input}:checked ~ & {
+ border-width: ${RING_SIZE}px;
+ border-color: ${wf(props => props.theme.selected)};
+ }
+
+ ${Input}:focus-visible ~ & {
+ box-shadow: 0 0 0 0.5px ${wf(props => props.theme.background)},
+ 0 0 2px 2px ${OUTLINE_ON};
+
+ &:hover {
+ box-shadow: 0 0 0 0.5px ${wf(props => props.theme.background)},
+ 0 0 2px 2px ${OUTLINE_ON}, 0 0 4px ${OUTLINE_HOVER};
+ }
+ }
+
+ &:hover {
+ box-shadow: 0 0 4px ${OUTLINE_HOVER};
+ }
+
+ ${props =>
+ props.disabled &&
+ css`
+ opacity: 0.4;
+ &:hover {
+ box-shadow: none;
+ }
+ `}
+`;
+
+// @component
+const InputRadio = styled(props => (
+
+
+
+
+))``;
+
+export default InputRadio;
diff --git a/packages/react-forms/src/InputRadio/index.test.js b/packages/react-forms/src/InputRadio/index.test.js
new file mode 100644
index 00000000..16e714a2
--- /dev/null
+++ b/packages/react-forms/src/InputRadio/index.test.js
@@ -0,0 +1,16 @@
+// @flow
+import React from 'react';
+import { mount } from 'enzyme';
+import InputRadio from '.';
+
+jest.mock('nanoid', () => () => 'random-id');
+
+it('renders an InputRadio', () => {
+ const wrapper = mount( );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('renders a disabled InputRadio', () => {
+ const wrapper = mount( );
+ expect(wrapper).toMatchSnapshot();
+});
diff --git a/packages/react-forms/src/index.js b/packages/react-forms/src/index.js
index 08c3ba41..9bae264d 100644
--- a/packages/react-forms/src/index.js
+++ b/packages/react-forms/src/index.js
@@ -3,6 +3,7 @@ export { default as InputColor } from './InputColor';
export { default as InputFile } from './InputFile';
export { default as InputGroup } from './InputGroup';
export { default as InputNumber } from './InputNumber';
+export { default as InputRadio } from './InputRadio';
export { default as InputRange } from './InputRange';
export { default as InputText } from './InputText';
export { default as InputToggle } from './InputToggle';
diff --git a/packages/react-forms/src/index.test.js b/packages/react-forms/src/index.test.js
index 43171b9f..35840663 100644
--- a/packages/react-forms/src/index.test.js
+++ b/packages/react-forms/src/index.test.js
@@ -8,6 +8,7 @@ Array [
"InputFile",
"InputGroup",
"InputNumber",
+ "InputRadio",
"InputRange",
"InputText",
"InputToggle",