diff --git a/e2e/output/components/Ribbon/baseline/chrome_headless.png b/e2e/output/components/Ribbon/baseline/chrome_headless.png
new file mode 100644
index 000000000..ecd70c2b4
Binary files /dev/null and b/e2e/output/components/Ribbon/baseline/chrome_headless.png differ
diff --git a/packages/Ribbon/README.md b/packages/Ribbon/README.md
new file mode 100644
index 000000000..7acbad2ea
--- /dev/null
+++ b/packages/Ribbon/README.md
@@ -0,0 +1 @@
+# TDS Community: Ribbon
diff --git a/packages/Ribbon/Ribbon.jsx b/packages/Ribbon/Ribbon.jsx
new file mode 100644
index 000000000..09ca8fb67
--- /dev/null
+++ b/packages/Ribbon/Ribbon.jsx
@@ -0,0 +1,31 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import safeRest from '@tds/shared-safe-rest'
+
+import styles from './Ribbon.scss'
+
+/** Ribbon component for focusing attention onto a sale or special feature.
+ * @version ./package.json
+ */
+const Ribbon = ({ ribbonCopy, ...rest }) => {
+ return (
+
+ {
+
+ {ribbonCopy}
+
+ }
+
+ )
+}
+
+Ribbon.propTypes = {
+ ribbonCopy: PropTypes.string,
+}
+
+Ribbon.defaultProps = {
+ ribbonCopy: '',
+}
+
+export default Ribbon
diff --git a/packages/Ribbon/Ribbon.md b/packages/Ribbon/Ribbon.md
new file mode 100644
index 000000000..13deefb39
--- /dev/null
+++ b/packages/Ribbon/Ribbon.md
@@ -0,0 +1,3 @@
+```jsx
+
+```
diff --git a/packages/Ribbon/Ribbon.scss b/packages/Ribbon/Ribbon.scss
new file mode 100644
index 000000000..0c78954c1
--- /dev/null
+++ b/packages/Ribbon/Ribbon.scss
@@ -0,0 +1,24 @@
+.ribbonStyle {
+ background: #4B286D;
+ color: #FFFFFF;
+ padding: 8px 30px 8px 15px;
+ margin: 16px 0;
+ position: relative;
+ font-size: 1rem;
+ display: inline-block;
+ max-width: 100%;
+ min-width: 126px;
+ min-height: 40px;
+
+ &:after {
+ content: '';
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ width: 0;
+ height: 0;
+ border-right: 13px solid white;
+ border-top: 20px solid transparent;
+ border-bottom: 20px solid transparent;
+ };
+};
diff --git a/packages/Ribbon/__tests__/Ribbon.spec.jsx b/packages/Ribbon/__tests__/Ribbon.spec.jsx
new file mode 100644
index 000000000..01f7f91f5
--- /dev/null
+++ b/packages/Ribbon/__tests__/Ribbon.spec.jsx
@@ -0,0 +1,32 @@
+import React from 'react'
+import { shallow } from 'enzyme'
+
+import Ribbon from '../Ribbon'
+
+describe('Ribbon', () => {
+ const doShallow = (
+ props = {
+ ribbonCopy: 'Prop Text',
+ }
+ ) => shallow()
+
+ it('matches snapshot with ribbonCopy prop', () => {
+ const ribbon = doShallow()
+ expect(ribbon).toMatchSnapshot()
+ })
+
+ it('matches snapshot with empty ribbonCopy prop', () => {
+ const ribbon = doShallow()
+ ribbon.setProps({ ribbonCopy: '' })
+ expect(ribbon).toMatchSnapshot()
+ })
+
+ it('does not allow custom CSS', () => {
+ const ribbon = doShallow({
+ className: 'my-custom-class',
+ style: { color: 'hotpink' },
+ })
+ expect(ribbon).not.toHaveProp('className', 'my-custom-class')
+ expect(ribbon).not.toHaveProp('style')
+ })
+})
diff --git a/packages/Ribbon/__tests__/__snapshots__/Ribbon.spec.jsx.snap b/packages/Ribbon/__tests__/__snapshots__/Ribbon.spec.jsx.snap
new file mode 100644
index 000000000..108b62f5c
--- /dev/null
+++ b/packages/Ribbon/__tests__/__snapshots__/Ribbon.spec.jsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Ribbon matches snapshot with empty ribbonCopy prop 1`] = `
+
+
+
+`;
+
+exports[`Ribbon matches snapshot with ribbonCopy prop 1`] = `
+
+
+ Prop Text
+
+
+`;
diff --git a/packages/Ribbon/index.cjs.js b/packages/Ribbon/index.cjs.js
new file mode 100644
index 000000000..7c84beb02
--- /dev/null
+++ b/packages/Ribbon/index.cjs.js
@@ -0,0 +1,4 @@
+require('./dist/index.css')
+const Ribbon = require('./dist/index.cjs')
+
+module.exports = Ribbon
diff --git a/packages/Ribbon/index.es.js b/packages/Ribbon/index.es.js
new file mode 100644
index 000000000..5c636bcd1
--- /dev/null
+++ b/packages/Ribbon/index.es.js
@@ -0,0 +1,4 @@
+import './dist/index.css'
+import Ribbon from './dist/index.es'
+
+export default Ribbon
diff --git a/packages/Ribbon/package.json b/packages/Ribbon/package.json
new file mode 100644
index 000000000..1f74b75c0
--- /dev/null
+++ b/packages/Ribbon/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "@tds/community-ribbon",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.cjs.js",
+ "module": "index.es.js",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/telus/tds-community.git"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "author": "TELUS digital",
+ "engines": {
+ "node": ">=8"
+ },
+ "bugs": {
+ "url": "https://github.com/telus/tds-community/issues"
+ },
+ "homepage": "http://tds.telus.com",
+ "peerDependencies": {
+ "react": ">=15",
+ "react-dom": ">=15"
+ },
+ "dependencies": {
+ "prop-types": "^15.6.2"
+ },
+ "devDependencies": {
+ "@tds/shared-safe-rest": "^1.0.0"
+ }
+}
diff --git a/packages/Ribbon/rollup.config.js b/packages/Ribbon/rollup.config.js
new file mode 100644
index 000000000..3bbd01b73
--- /dev/null
+++ b/packages/Ribbon/rollup.config.js
@@ -0,0 +1,7 @@
+import configure from '../../config/rollup.config'
+import { dependencies } from './package.json'
+
+export default configure({
+ input: './Ribbon.jsx',
+ dependencies,
+})