diff --git a/src/components/SiteAlert/SiteAlert.stories.tsx b/src/components/SiteAlert/SiteAlert.stories.tsx
new file mode 100644
index 0000000000..83bcff27d5
--- /dev/null
+++ b/src/components/SiteAlert/SiteAlert.stories.tsx
@@ -0,0 +1,149 @@
+/* eslint-disable jsx-a11y/anchor-is-valid */
+
+import React from 'react'
+
+import { SiteAlert } from './SiteAlert'
+import { Link } from '../Link/Link'
+
+export default {
+ title: 'Components/SiteAlert',
+ component: SiteAlert,
+ parameters: {
+ docs: {
+ description: {
+ component: `
+### USWDS 2.0 SiteAlert component
+
+Source: http://designsystem.digital.gov/components/site-alert
+`,
+ },
+ },
+ },
+ argTypes: {
+ slim: {
+ control: {
+ type: 'boolean',
+ },
+ },
+ showIcon: {
+ control: {
+ type: 'boolean',
+ },
+ },
+ variant: {
+ control: {
+ type: 'select',
+ options: ['info', 'emergency'],
+ },
+ defaultValue: 'info',
+ },
+ },
+}
+
+const infoHeading = 'Short alert message'
+
+const additionalContext = (
+
+ Additional context and followup information including{' '}
+
+ a link
+
+ .
+
+)
+
+const emergencyHeading = 'Emergency alert message'
+
+const infoWithList = (
+
+ -
+ The primary informational message and{` `}
+ a link
+ {` `}for supporting context.
+
+ -
+ Another message,{` `}
+ and another link.
+
+ - A final informational message.
+
+)
+
+const emergencyWithList = (
+
+ -
+ The primary emergency message and{` `}
+ a link
+ {` `}for supporting context.
+
+ -
+ Another message,{` `}
+ and another link.
+
+ - A final emergency message.
+
+)
+
+const shortAlertContent = (
+
+ Short alert message.
+ Additional context and followup information including
+ a link.
+
+)
+
+export const standardInformationalSiteAlert = (): React.ReactElement => (
+
+ {additionalContext}
+
+)
+
+export const standardEmergencySiteAlert = (): React.ReactElement => (
+
+ {additionalContext}
+
+)
+
+export const informationalAlertWithNoHeader = (): React.ReactElement => (
+ {shortAlertContent}
+)
+
+export const emergencyAlertWithNoHeader = (): React.ReactElement => (
+ {shortAlertContent}
+)
+
+export const informationalAlertWithList = (): React.ReactElement => (
+
+ {infoWithList}
+
+)
+
+export const emergencyAlertWithList = (): React.ReactElement => (
+
+ {emergencyWithList}
+
+)
+
+export const slimEmergencyAlert = (): React.ReactElement => (
+
+ {shortAlertContent}
+
+)
+
+export const emergencyAlertNoIcon = (): React.ReactElement => (
+
+ {shortAlertContent}
+
+)
+
+export const alertWithCustomControls = (argTypes): React.ReactElement => (
+
+ {shortAlertContent}
+
+)
diff --git a/src/components/SiteAlert/SiteAlert.test.tsx b/src/components/SiteAlert/SiteAlert.test.tsx
new file mode 100644
index 0000000000..4bc9fc2d45
--- /dev/null
+++ b/src/components/SiteAlert/SiteAlert.test.tsx
@@ -0,0 +1,124 @@
+/* eslint-disable jsx-a11y/anchor-is-valid, react/jsx-key */
+import React from 'react'
+import { render } from '@testing-library/react'
+
+import { Link } from '../Link/Link'
+
+import { SiteAlert } from './SiteAlert'
+
+const testChildren = (
+
+ some default text
+ with a link.
+
+)
+
+const testDefaultProps = {
+ heading: 'test heading',
+ children: testChildren,
+}
+
+const testChildrenWithList = (
+
+ -
+ some default text
+ with a link
+
+ -
+ another list item
+ with a link
+
+ - another list item, no link
+
+)
+
+describe('SiteAlert component', () => {
+ it('renders without errors', () => {
+ const { getByTestId, getByRole } = render(
+
+ )
+
+ expect(getByTestId('siteAlert')).toBeInTheDocument()
+ expect(getByRole('link')).toBeInTheDocument()
+ })
+
+ it('accepts a className', () => {
+ const { getByTestId } = render(
+
+ )
+
+ expect(getByTestId('siteAlert')).toHaveClass(
+ 'usa-site-alert usa-site-alert--info custom-class-name'
+ )
+ })
+
+ it('accepts a custom aria-label', () => {
+ const { getByTestId } = render(
+
+ )
+
+ expect(getByTestId('siteAlert')).toHaveAttribute(
+ 'aria-label',
+ 'custom aria label'
+ )
+ })
+
+ it('renders a passed in heading', () => {
+ const { getByRole, queryByText } = render(
+
+ )
+
+ const heading = getByRole('heading')
+ expect(heading).toBeInTheDocument()
+ expect(heading).toHaveClass('usa-alert__heading')
+ expect(queryByText('test heading')).toBeInTheDocument()
+ })
+
+ it('renders emergency site alert without errors', () => {
+ const { getByTestId } = render(
+
+ )
+
+ expect(getByTestId('siteAlert')).toHaveClass(
+ 'usa-site-alert usa-site-alert--emergency'
+ )
+ })
+
+ it('renders passed in link', () => {
+ const { getByRole } = render(
+ {testChildren}
+ )
+
+ expect(getByRole('link')).toBeInTheDocument()
+ expect(getByRole('link')).toHaveClass('usa-link')
+ })
+
+ it('renders a passed in list', () => {
+ const { getAllByRole } = render(
+ {testChildrenWithList}
+ )
+ expect(getAllByRole('link')).toHaveLength(2)
+ })
+
+ it('renders slim and no icon when passed both, and does not apply no-header class', () => {
+ const { getByTestId } = render(
+
+ {testChildren}
+
+ )
+ expect(getByTestId('siteAlert')).toHaveClass(
+ 'usa-site-alert usa-site-alert--info usa-site-alert--no-icon usa-site-alert--slim'
+ )
+ expect(getByTestId('siteAlert')).not.toHaveClass(
+ 'usa-site-alert--no-heading'
+ )
+ })
+})
diff --git a/src/components/SiteAlert/SiteAlert.tsx b/src/components/SiteAlert/SiteAlert.tsx
new file mode 100644
index 0000000000..67639a75b6
--- /dev/null
+++ b/src/components/SiteAlert/SiteAlert.tsx
@@ -0,0 +1,49 @@
+import React from 'react'
+import classnames from 'classnames'
+
+interface SiteAlertProps {
+ variant: 'info' | 'emergency'
+ children: React.ReactNode
+ heading?: string
+ showIcon?: boolean
+ slim?: boolean
+ className?: string
+}
+
+export const SiteAlert = ({
+ variant,
+ children,
+ heading,
+ showIcon = true,
+ slim = false,
+ className,
+ ...sectionProps
+}: SiteAlertProps & JSX.IntrinsicElements['section']): React.ReactElement => {
+ const classes = classnames(
+ 'usa-site-alert',
+ {
+ 'usa-site-alert--info': variant === 'info',
+ 'usa-site-alert--emergency': variant === 'emergency',
+ 'usa-site-alert--no-heading': heading === undefined && !slim,
+ 'usa-site-alert--no-icon': !showIcon,
+ 'usa-site-alert--slim': slim,
+ },
+ className
+ )
+ return (
+
+
+
+ {heading &&
{heading}
}
+ {children}
+
+
+
+ )
+}
+
+export default SiteAlert
diff --git a/src/index.ts b/src/index.ts
index 15899dc348..81f5072761 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -90,6 +90,8 @@ export { StepIndicatorStep } from './components/stepindicator/StepIndicatorStep/
export { Search } from './components/Search/Search'
+export { SiteAlert } from './components/SiteAlert/SiteAlert'
+
/** Truss-designed components */
export {
Modal,