diff --git a/common/changes/pcln-design-system/add-flashcard-component_2023-08-16-04-48.json b/common/changes/pcln-design-system/add-flashcard-component_2023-08-16-04-48.json
new file mode 100644
index 0000000000..1a3a20f611
--- /dev/null
+++ b/common/changes/pcln-design-system/add-flashcard-component_2023-08-16-04-48.json
@@ -0,0 +1,10 @@
+{
+  "changes": [
+    {
+      "packageName": "pcln-design-system",
+      "comment": "add Flashcard component",
+      "type": "minor"
+    }
+  ],
+  "packageName": "pcln-design-system"
+}
\ No newline at end of file
diff --git a/packages/core/src/Flashcard/Flashcard.spec.tsx b/packages/core/src/Flashcard/Flashcard.spec.tsx
new file mode 100644
index 0000000000..f18ca1c88a
--- /dev/null
+++ b/packages/core/src/Flashcard/Flashcard.spec.tsx
@@ -0,0 +1,69 @@
+import { render, screen } from '@testing-library/react'
+import React from 'react'
+import { Flashcard } from '..'
+
+const frontside = 'Front'
+const backside = 'Back'
+const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
+
+describe('Flashcard', () => {
+  it('renders the front content', () => {
+    render({frontside})
+    const front = screen.getByText(frontside)
+    const back = screen.queryByText(backside)
+    expect(front).toBeInTheDocument()
+    expect(back).not.toBeInTheDocument()
+  })
+
+  it('renders the back content when flipped', async () => {
+    render({frontside})
+
+    const front = screen.getByText(frontside)
+
+    front.click()
+    await wait(1000)
+
+    const front2 = screen.queryByText(frontside)
+    const back = screen.getByText(backside)
+    expect(front2).not.toBeInTheDocument()
+    expect(back).toBeInTheDocument()
+  })
+
+  it('renders the front content when dismissed', async () => {
+    const handleChange = jest.fn()
+
+    render(
+      <>
+        outside
+        
+          {frontside}
+        
+      >
+    )
+
+    const outside = screen.getByText('outside')
+    outside.click()
+    await wait(1000)
+
+    const front = screen.getByText(frontside)
+    const back = screen.queryByText(backside)
+    expect(front).toBeInTheDocument()
+    expect(back).not.toBeInTheDocument()
+    expect(handleChange).toHaveBeenCalled()
+  })
+
+  it('handles controlled state when open', async () => {
+    render(
+      
+        {frontside}
+      
+    )
+
+    const front = screen.getByText(frontside)
+    front.click()
+    await wait(1000)
+
+    const back = screen.queryByText(backside)
+    expect(back).not.toBeInTheDocument()
+  })
+})
diff --git a/packages/core/src/Flashcard/Flashcard.stories.args.tsx b/packages/core/src/Flashcard/Flashcard.stories.args.tsx
new file mode 100644
index 0000000000..7d59910598
--- /dev/null
+++ b/packages/core/src/Flashcard/Flashcard.stories.args.tsx
@@ -0,0 +1,30 @@
+import type { IFlashcardProps } from '..'
+import { borderRadii, Grid, paletteColors, shadows } from '..'
+
+import type { ArgTypes } from '@storybook/react'
+import React from 'react'
+import { flashCardRotations } from './Flashcard.styled'
+
+export const argTypes: Partial> = {
+  backside: { table: { disable: true } },
+  backsideBg: { control: { type: 'select' }, options: paletteColors },
+  bg: { control: { type: 'select' }, options: paletteColors },
+  borderRadius: { control: { type: 'select' }, options: Object.keys(borderRadii) },
+  boxShadowSize: { control: { type: 'select' }, options: Object.keys(shadows) },
+  children: { table: { disable: true } },
+  duration: { control: { type: 'number' } },
+  open: { control: { type: 'boolean' } },
+  perspective: { control: { type: 'number' } },
+  rotation: { control: { type: 'select' }, options: flashCardRotations },
+}
+
+export const defaultArgs: Partial = {
+  backside: Back,
+  backsideBg: 'secondary.light',
+  bg: 'primary.light',
+  borderRadius: 'xl',
+  children: Front,
+  duration: 0.5,
+  perspective: 200,
+  rotation: 'y',
+}
diff --git a/packages/core/src/Flashcard/Flashcard.stories.tsx b/packages/core/src/Flashcard/Flashcard.stories.tsx
new file mode 100644
index 0000000000..eb1ace2884
--- /dev/null
+++ b/packages/core/src/Flashcard/Flashcard.stories.tsx
@@ -0,0 +1,197 @@
+import type { Meta, StoryObj } from '@storybook/react'
+import { ArrowLeft } from 'pcln-icons'
+import React, { useState } from 'react'
+
+import type { IFlashcardProps, IGridProps } from '..'
+import { Button, Flashcard, Grid, IconButton, Text } from '..'
+import { argTypes, defaultArgs } from './Flashcard.stories.args'
+
+type FlashcardStory = StoryObj
+
+const ExampleImage = () => (
+  
+)
+
+export const Playground: FlashcardStory = {
+  render: (args) => (
+    
+      ,
+    
+  ),
+}
+
+export const Multiple: FlashcardStory = {
+  render: (args) => (
+    
+      
+      
+      
+      
+    
+  ),
+}
+
+export const DifferentSizes: FlashcardStory = {
+  render: (args) => (
+    
+      Back}>
+        Front
+      
+    
+  ),
+}
+
+const GridCell = (props: IGridProps) => 
+export const ContentShift: FlashcardStory = {
+  render: (args) => (
+    
+      Top Left
+      Top
+      Top Right
+      Left
+      
+        
+              Back
+              
+              
+              Lorem ipsum dolor sit amet consectetur adipisicing elit.
+            
+          }
+        >
+          
+            Front
+          
+        
+      
+      Right
+      Bottom Left
+      Bottom
+      Bottom Right
+    
+  ),
+}
+
+export const OverflowContent: FlashcardStory = {
+  ...Playground,
+  args: {
+    ...defaultArgs,
+    children: (
+      
+        
+          Front
+          
+            Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore accusamus mollitia ipsa aliquid,
+            placeat sint consequatur inventore doloribus in culpa dolorum excepturi possimus ab. Deleniti
+            repellat quo aspernatur nihil. Maiores.
+          
+        
+      
+    ),
+    backside: (
+      
+        
+          Back
+          
+            Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore accusamus mollitia ipsa aliquid,
+            placeat sint consequatur inventore doloribus in culpa dolorum excepturi possimus ab. Deleniti
+            repellat quo aspernatur nihil. Maiores.
+          
+        
+      
+    ),
+  },
+}
+
+export const Image: FlashcardStory = {
+  ...Playground,
+  args: {
+    ...defaultArgs,
+    perspective: 400,
+    children: (
+      
+        
+      
+    ),
+    backside: (
+      
+        
+          
+        
+        
+        Beach
+        
+          Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolore accusamus mollitia ipsa aliquid,
+          placeat sint consequatur inventore doloribus in culpa dolorum excepturi possimus ab. Deleniti
+          repellat quo aspernatur nihil. Maiores.
+        
+      
+    ),
+  },
+}
+
+export const Controlled: FlashcardStory = {
+  render: (args) => {
+    const [open, setOpen] = useState(false)
+
+    const flipButton = (
+      }
+        style={{ position: 'absolute', top: '1rem', left: '1rem', border: '2px solid currentcolor' }}
+        onClick={() => setOpen(!open)}
+        borderRadius='full'
+      />
+    )
+
+    return (
+      
+        
+         {flipButton} Back }>
+           {flipButton} Front 
+        
+      
+    )
+  },
+  argTypes: { open: { table: { disable: true } } },
+  args: { perspective: 300 },
+}
+
+const insideProps = { width: 200, height: 200, placeItems: 'center', p: 3 }
+const outsideProps = { width: 300, height: 300, placeItems: 'center', p: 3 }
+export const Nested: FlashcardStory = {
+  render: (args) => (
+    
+       Outside Back }>
+        
+          Outside Front
+           Inside Back }>
+            Inside Front
+          
+        
+      
+    
+  ),
+  args: {
+    ...defaultArgs,
+    boxShadowSize: 'md',
+  },
+}
+
+const meta: Meta = {
+  title: 'Flashcard',
+  component: Flashcard,
+  args: defaultArgs,
+  argTypes: argTypes,
+}
+
+export default meta
diff --git a/packages/core/src/Flashcard/Flashcard.styled.tsx b/packages/core/src/Flashcard/Flashcard.styled.tsx
new file mode 100644
index 0000000000..a06b17f701
--- /dev/null
+++ b/packages/core/src/Flashcard/Flashcard.styled.tsx
@@ -0,0 +1,37 @@
+import type { IFlashcardProps } from '..'
+
+import themeGet from '@styled-system/theme-get'
+import type { ForwardRefComponent, HTMLMotionProps, TargetAndTransition } from 'framer-motion'
+import { motion } from 'framer-motion'
+import styled from 'styled-components'
+
+export const flashCardRotations = ['x', 'y', 'x-reverse', 'y-reverse'] as const
+export type FlashcardRotation = (typeof flashCardRotations)[number]
+
+export const flashcardRotations: Record = {
+  x: { rotateX: 180 },
+  y: { rotateY: 180 },
+  'x-reverse': { rotateX: -180 },
+  'y-reverse': { rotateY: -180 },
+  reset: { rotateX: 0, rotateY: 0 },
+} as const
+
+export type FlashcardMotionProps = Partial & HTMLMotionProps<'div'>
+
+export type FlashcardContainerProps = HTMLMotionProps<'div'> &
+  Partial>
+
+export const CardContainer: (props: FlashcardContainerProps) => JSX.Element = styled(motion.div)`
+  perspective: ${(props: FlashcardContainerProps) => props.perspective}px;
+`
+
+export const OuterCardMotion: ForwardRefComponent = styled(motion.div)``
+
+export const InnerCardMotion: ForwardRefComponent = styled(motion.div)`
+  background-color: ${(props: FlashcardMotionProps) => themeGet(`palette.${props.bg}`)(props)};
+  border-radius: ${(props: FlashcardMotionProps) => themeGet(`borderRadii.${props.borderRadius}`)(props)};
+  box-shadow: ${(props: FlashcardMotionProps) => themeGet(`shadows.${props.boxShadowSize}`)(props)};
+  &:hover {
+    box-shadow: ${(props: FlashcardMotionProps) => themeGet(`shadows.2xl`)(props)};
+  }
+`
diff --git a/packages/core/src/Flashcard/Flashcard.tsx b/packages/core/src/Flashcard/Flashcard.tsx
new file mode 100644
index 0000000000..074688e230
--- /dev/null
+++ b/packages/core/src/Flashcard/Flashcard.tsx
@@ -0,0 +1,98 @@
+import type { BorderRadius, BoxShadowSize, PaletteColor } from '..'
+import {
+  CardContainer,
+  FlashcardRotation,
+  InnerCardMotion,
+  OuterCardMotion,
+  flashcardRotations,
+} from './Flashcard.styled'
+
+import React, { useEffect, useRef, useState } from 'react'
+
+export interface IFlashcardProps {
+  backside: React.ReactNode
+  backsideBg?: PaletteColor
+  bg?: PaletteColor
+  borderRadius?: BorderRadius
+  boxShadowSize?: BoxShadowSize
+  children: React.ReactNode
+  defaultOpen?: boolean
+  duration?: number
+  onOpenChange?: (open: boolean) => void
+  open?: boolean
+  perspective?: number | string
+  rotation?: FlashcardRotation
+}
+
+const Flashcard = ({
+  backside,
+  backsideBg,
+  bg,
+  borderRadius = 'xl',
+  boxShadowSize,
+  children,
+  defaultOpen = false,
+  duration = 0.5,
+  onOpenChange,
+  open,
+  perspective = 200,
+  rotation = 'y',
+}: IFlashcardProps) => {
+  const [_open, setOpen] = useState(open ?? defaultOpen)
+  const [_bg, setBg] = useState(_open ? backsideBg : bg)
+  const [_children, setChildren] = useState(_open ? backside : children)
+  const ref = useRef(null)
+
+  useEffect(() => setChildren(_open ? backside : children), [children, backside])
+  useEffect(() => setBg(_open ? backsideBg : bg), [bg, backsideBg])
+
+  const handleOpenChange = (newOpen: boolean) => {
+    onOpenChange?.(newOpen)
+    setOpen(newOpen)
+    setTimeout(() => {
+      setChildren(newOpen ? backside : children)
+      setBg(newOpen ? backsideBg : bg)
+    }, (duration * 1000) / 2)
+  }
+
+  useEffect(() => handleOpenChange(open), [open])
+
+  useEffect(() => {
+    if (open !== undefined) return
+    const handleOutsideClick = (event: MouseEvent) => {
+      if (ref.current && !ref.current.contains(event.target)) handleOpenChange(false)
+    }
+    document.addEventListener('mousedown', handleOutsideClick)
+    return () => document.removeEventListener('mousedown', handleOutsideClick)
+  }, [ref])
+
+  return (
+    
+      
+         {
+                  e.stopPropagation()
+                  handleOpenChange(true)
+                }
+              : undefined
+          }
+          ref={ref}
+          transition={{ duration }}
+        >
+          {_children}
+        
+      
+    
+  )
+}
+
+export default Flashcard
diff --git a/packages/core/src/Flashcard/index.ts b/packages/core/src/Flashcard/index.ts
new file mode 100644
index 0000000000..6be4be21fe
--- /dev/null
+++ b/packages/core/src/Flashcard/index.ts
@@ -0,0 +1,3 @@
+export type { IFlashcardProps } from './Flashcard'
+
+export { default as Flashcard } from './Flashcard'
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 216dcb6cd4..88a607dc9d 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -2,6 +2,7 @@ import * as storybookArgs from './storybook/args'
 
 export type { IButtonProps } from './Button'
 export type { IDialogProps } from './Dialog'
+export type { IFlashcardProps } from './Flashcard'
 export type { IGridProps } from './Grid'
 
 export { Absolute } from './Absolute'
@@ -24,6 +25,7 @@ export { Dialog } from './Dialog'
 export { Divider } from './Divider'
 export { DotLoader } from './DotLoader'
 export { Flag } from './Flag'
+export { Flashcard } from './Flashcard'
 export { Flex } from './Flex'
 export { FormField, InputField } from './FormField'
 export { GenericBanner } from './GenericBanner'
diff --git a/packages/core/src/theme/theme.ts b/packages/core/src/theme/theme.ts
index 84e013d2ea..d6f05a34a6 100644
--- a/packages/core/src/theme/theme.ts
+++ b/packages/core/src/theme/theme.ts
@@ -312,6 +312,8 @@ export const shadows = {
     '0 -1px 0 0 rgba(0,0,0,0.03),0 24px 72px 0 rgba(0,0,0,0.48),0 8px 16px 0 rgba(0,0,0,0.12),0 24px 64px 0 rgba(0,0,0,0.2)',
 }
 
+export type BoxShadowSize = keyof typeof shadows
+
 export const textShadows = {
   sm: `0 1px 2px rgba(0,0,0,0.5)`,
   md: `0 2px 4px rgba(0,0,0,0.5)`,