diff --git a/src/components/Accordion/Accordion.examples.story.tsx b/src/components/Accordion/Accordion.examples.story.tsx
new file mode 100644
index 00000000..d2dea90d
--- /dev/null
+++ b/src/components/Accordion/Accordion.examples.story.tsx
@@ -0,0 +1,135 @@
+import React from 'react';
+import { Accordion } from './Accordion';
+import { Layout } from '../../storybook';
+import styled from 'styled-components';
+import { Gear } from '../../icons';
+import { rem } from 'polished';
+import { core } from '../../tokens';
+
+export default {
+ title: 'components/Accordion/examples',
+ component: Accordion,
+ argTypes: {
+ allowMultiple: { control: { disable: true } },
+ defaultIndex: { control: { disable: true } },
+ format: { control: { disable: true } },
+ },
+};
+
+export function AccordionWithSubcopy({ args }) {
+ return (
+
+
+
+ Accordion content
+
+
+
+ );
+}
+
+AccordionWithSubcopy.storyName = 'Accordion - subcopy';
+
+export function AccordionWithIcon({ args }) {
+ return (
+
+
+ }
+ >
+ Accordion content
+
+
+
+ );
+}
+
+const GearIcon = styled(Gear)`
+ width: ${rem(22)};
+ margin-right: ${rem(10)};
+ path {
+ fill: ${core.color.text.primary};
+ }
+`;
+
+AccordionWithIcon.storyName = 'Accordion - icon';
+
+export function DisabledAccordion({ args }) {
+ return (
+
+
+
+ Accordion content
+
+
+
+ );
+}
+
+DisabledAccordion.storyName = 'Accordion - disabled';
+
+export function AccordionWithError({ args }) {
+ return (
+
+
+
+ Accordion content
+
+
+
+ );
+}
+
+AccordionWithError.storyName = 'Accordion - error';
+
+export function AccordionWithAllowMultipleFalse({ args }) {
+ return (
+
+
+
+ Accordion content
+
+
+ Accordion content
+
+
+ Accordion content
+
+
+
+ );
+}
+
+AccordionWithAllowMultipleFalse.storyName =
+ 'Accordion - allowMultiple is false';
+
+export function AccordionAllowMultiple({ args }) {
+ return (
+
+
+
+ Accordion content
+
+
+ Accordion content
+
+
+ Accordion content
+
+
+
+ );
+}
+
+AccordionAllowMultiple.storyName =
+ 'Accordion - allowMultiple is true (default)';
diff --git a/src/components/Accordion/Accordion.minors.tsx b/src/components/Accordion/Accordion.minors.tsx
new file mode 100644
index 00000000..ec653b26
--- /dev/null
+++ b/src/components/Accordion/Accordion.minors.tsx
@@ -0,0 +1,77 @@
+import React, { useState } from 'react';
+
+import {
+ Content,
+ ChevronUp,
+ CircleWarningIcon,
+ Header,
+ StyledChevronDown,
+ Subcopy,
+ Title,
+ TitleContainer,
+ TriggerContainer,
+ Wrapper,
+} from './Accordion.style';
+import { MinorComponent } from '../../utils';
+import { AccordionItemProps } from './Accordion.types';
+
+export interface Minors {
+ Item: MinorComponent;
+}
+
+export function Item({
+ children,
+ title,
+ format,
+ index,
+ allowMultiple,
+ defaultActive,
+ setActiveIndex,
+ itemActive,
+ subcopy = '',
+ icon,
+ hasError = false,
+ disabled = false,
+}: AccordionItemProps) {
+ const [active, setActive] = useState(defaultActive);
+ const isActive = allowMultiple
+ ? active && !disabled
+ : itemActive && !disabled;
+
+ return (
+
+ {
+ if (allowMultiple) {
+ setActive(!active);
+ } else {
+ setActiveIndex({ index });
+ }
+ }}
+ tabIndex={0}
+ format={format}
+ active={isActive}
+ >
+
+ {hasError && }
+ {!hasError && icon && icon}
+
+ {title}
+ {subcopy && {subcopy}}
+
+
+ {isActive ? (
+
+ ) : (
+
+ )}
+
+ {isActive && {children}}
+
+ );
+}
diff --git a/src/components/Accordion/Accordion.props.story.tsx b/src/components/Accordion/Accordion.props.story.tsx
new file mode 100644
index 00000000..85f377fc
--- /dev/null
+++ b/src/components/Accordion/Accordion.props.story.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import styled, { css } from 'styled-components';
+import { rem } from 'polished';
+
+import { Accordion } from './Accordion';
+
+export default {
+ title: 'components/Accordion/props',
+ component: Accordion,
+ argTypes: {
+ allowMultiple: { control: { disable: true } },
+ defaultIndex: { control: { disable: true } },
+ format: { control: { disable: true } },
+ },
+};
+
+const formats = ['basic', 'secondary'];
+
+export function Formats({ args }) {
+ return (
+
+ {formats.map((format) => (
+
+
+ Accordion content
+
+
+ ))}
+
+ );
+}
+
+const Container = styled.div`
+ width: 50%;
+ display: flex;
+ flex-direction: column;
+ gap: ${rem(8)};
+`;
diff --git a/src/components/Accordion/Accordion.story.tsx b/src/components/Accordion/Accordion.story.tsx
new file mode 100644
index 00000000..0dd4a137
--- /dev/null
+++ b/src/components/Accordion/Accordion.story.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { Story } from '@storybook/react';
+
+import { Accordion } from './Accordion';
+import { Props } from './Accordion.types';
+import styled from 'styled-components';
+import { Gear } from '../../icons';
+import { rem } from 'polished';
+
+export default {
+ title: 'components/Accordion',
+ component: Accordion,
+};
+
+const Template: Story = (args) => {
+ return (
+
+
+
+ Accordion content
+
+
+ Accordion content
+
+
+
+ );
+};
+
+const Container = styled.div`
+ width: 50%;
+`;
+
+export const Controls = Template.bind({});
+Controls.storyName = 'Accordion';
diff --git a/src/components/Accordion/Accordion.style.ts b/src/components/Accordion/Accordion.style.ts
new file mode 100644
index 00000000..c92382d5
--- /dev/null
+++ b/src/components/Accordion/Accordion.style.ts
@@ -0,0 +1,118 @@
+import { rem } from 'polished';
+import styled, { css } from 'styled-components';
+
+import { ChevronDown, CircleWarning } from '../../icons';
+import { Paragraph } from '../../typography';
+
+import { grayscale } from '../../color';
+import { core } from '../../tokens';
+
+export const AccordionStyled = styled.div`
+ display: flex;
+ flex-direction: column;
+ gap: ${rem(8)};
+`;
+
+export const Wrapper = styled.div<{
+ format: 'basic' | 'secondary';
+ active: boolean;
+ disabled: boolean;
+}>`
+ ${({ disabled }) =>
+ disabled &&
+ css`
+ pointer-events: none;
+ opacity: 0.4;
+ `}
+ ${({ active, theme, format }) =>
+ active &&
+ css`
+ background-color: ${format === 'basic'
+ ? theme.name === 'dark'
+ ? grayscale(800)
+ : grayscale(50)
+ : 'none'};
+ `}
+ border-radius: ${rem(10)};
+ color: ${core.color.text.primary};
+ ${({ active, theme, format }) =>
+ active &&
+ css`
+ border: ${format === 'secondary'
+ ? theme.name === 'dark'
+ ? `${rem(1)} solid ${grayscale(800)}`
+ : `${rem(1)} solid ${grayscale(50)}`
+ : 'none'};
+ `}
+`;
+
+export const TriggerContainer = styled.div<{
+ format: 'basic' | 'secondary';
+ active: boolean;
+}>`
+ display: flex;
+ justify-content: space-between;
+ cursor: pointer;
+ padding: ${rem(12)} ${rem(15)};
+ border-radius: ${rem(10)};
+ &:hover {
+ background-color: ${({ theme, format }) =>
+ format === 'basic'
+ ? theme.name === 'dark'
+ ? grayscale(800)
+ : grayscale(50)
+ : 'none'};
+ border: ${({ active, theme, format }) =>
+ !active && format === 'secondary'
+ ? theme.name === 'dark'
+ ? `${rem(1)} solid ${grayscale(800)}`
+ : `${rem(1)} solid ${grayscale(50)}`
+ : 'none'};
+ }
+`;
+
+export const Header = styled.div`
+ display: flex;
+ margin-right: ${rem(10)};
+`;
+
+export const TitleContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+`;
+
+export const Title = styled(Paragraph)`
+ font-size: ${rem(16)};
+ font-weight: 700;
+ margin-bottom: 0;
+`;
+
+export const Subcopy = styled(Paragraph)`
+ font-size: ${rem(14)};
+ font-weight: 400;
+ margin-bottom: -${rem(0.2)};
+`;
+
+export const CircleWarningIcon = styled(CircleWarning)`
+ width: ${rem(22)};
+ margin-right: ${rem(10)};
+ path {
+ fill: ${core.color.status.negative};
+ }
+`;
+
+export const StyledChevronDown = styled(ChevronDown)`
+ path {
+ fill: ${core.color.text.primary};
+ }
+`;
+
+export const ChevronUp = styled(StyledChevronDown)`
+ transform: rotate(180deg);
+`;
+
+export const Content = styled.div<{ active: boolean }>`
+ padding: ${rem(0)} ${rem(15)} ${rem(20)};
+ max-height: ${({ active }) => (active ? '100%' : '0')};
+ overflow: hidden;
+`;
diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx
new file mode 100644
index 00000000..16663220
--- /dev/null
+++ b/src/components/Accordion/Accordion.tsx
@@ -0,0 +1,42 @@
+import React, { cloneElement, useState } from 'react';
+
+import { withIris } from '../../utils';
+import { Item, Minors } from './Accordion.minors';
+import { Props } from './Accordion.types';
+import { AccordionStyled } from './Accordion.style';
+
+export const Accordion = withIris(
+ AccordionComponent
+);
+
+Accordion.Item = Item;
+
+function AccordionComponent({
+ children,
+ defaultIndex,
+ allowMultiple = true,
+ format = 'basic',
+}: Props) {
+ const [activeIndex, setActiveIndex] = useState(defaultIndex);
+
+ function childClone(child, i) {
+ return cloneElement(child, {
+ format,
+ index: i,
+ allowMultiple,
+ defaultActive: defaultIndex === i,
+ setActiveIndex: ({ index }) => {
+ setActiveIndex(index);
+ },
+ itemActive: !allowMultiple && activeIndex === i,
+ });
+ }
+
+ return (
+
+ {children.length > 1
+ ? children.map(childClone)
+ : childClone(children, 0)}
+
+ );
+}
diff --git a/src/components/Accordion/Accordion.types.ts b/src/components/Accordion/Accordion.types.ts
new file mode 100644
index 00000000..bf3af9bb
--- /dev/null
+++ b/src/components/Accordion/Accordion.types.ts
@@ -0,0 +1,26 @@
+import { IrisProps } from '../../utils';
+
+export type Props = IrisProps<
+ {
+ children: any;
+ allowMultiple?: boolean;
+ defaultIndex?: number;
+ format?: 'basic' | 'secondary';
+ },
+ HTMLDivElement
+>;
+
+export type AccordionItemProps = IrisProps<{
+ children: React.ReactElement;
+ title: string;
+ format: 'basic' | 'secondary';
+ index: number;
+ allowMultiple: boolean;
+ defaultActive: boolean;
+ setActiveIndex: ({ index }) => void;
+ itemActive: boolean;
+ subcopy?: string;
+ icon?: string;
+ hasError?: boolean;
+ disabled?: boolean;
+}>;