diff --git a/.changeset/wet-tools-exercise.md b/.changeset/wet-tools-exercise.md
new file mode 100644
index 0000000000..ba6eb8314f
--- /dev/null
+++ b/.changeset/wet-tools-exercise.md
@@ -0,0 +1,15 @@
+---
+'@backstage/core': minor
+---
+
+Adds the MarkdownContent component to render and display markdown input.
+
+```
+
+```
+
+Render and display the github flavored markdown [GFM](https://github.github.com/gfm/) input:
+
+```
+
+```
diff --git a/packages/core/package.json b/packages/core/package.json
index ec4411b390..a78fcc0a82 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -48,11 +48,13 @@
"react-dom": "^16.12.0",
"react-helmet": "6.1.0",
"react-hook-form": "^6.6.0",
+ "react-markdown": "^5.0.2",
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-sparklines": "^1.7.0",
"react-syntax-highlighter": "^13.5.1",
- "react-use": "^15.3.3"
+ "react-use": "^15.3.3",
+ "remark-gfm": "^1.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.26",
diff --git a/packages/core/src/components/MarkdownContent/MarkdownContent.stories.tsx b/packages/core/src/components/MarkdownContent/MarkdownContent.stories.tsx
new file mode 100644
index 0000000000..b3747971a7
--- /dev/null
+++ b/packages/core/src/components/MarkdownContent/MarkdownContent.stories.tsx
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { MarkdownContent } from './MarkdownContent';
+
+export default {
+ title: 'Data Display/MarkdownContent',
+ component: MarkdownContent,
+};
+
+const markdownGithubFlavored =
+ '# GFM\n' +
+ '\n' +
+ '## Autolink literals\n' +
+ '\n' +
+ 'www.example.com, https://example.com, and contact@example.com.\n' +
+ '\n' +
+ '## Strikethrough\n' +
+ '\n' +
+ '~one~ or ~~two~~ tildes.\n' +
+ '\n' +
+ '## Table\n' +
+ '\n' +
+ '| foo | bar |\n' +
+ '| --- | --- |\n' +
+ '| baz | bim |\n' +
+ '| buz | bum |\n' +
+ '| biz | bim |\n' +
+ '\n' +
+ '## Tasklist\n' +
+ '\n' +
+ '* [ ] to do\n' +
+ '* [x] done';
+
+const markdown =
+ '# Choreas Iovis\n' +
+ '\n' +
+ '## Incedere retenta\n' +
+ '\n' +
+ 'Lorem markdownum velamina [nupta amici aequoreis](http://est-quae.org/sic)\n' +
+ 'desertum factum premunt: falcato parvos nihil. Facietque vulnus tum dumque\n' +
+ 'reserato Maeandros insignia solidis, tot longi causa et nimium arcuerat altera\n' +
+ 'unus, in quis.\n' +
+ '\n' +
+ '1. Est qui dixere nullus\n' +
+ '2. Fuit obicit\n' +
+ '3. Vim patrem portae materiem ulla quod crater\n' +
+ '4. Rigido est magis raptor quid crepitante aequa\n' +
+ '5. Imago quis ignis tamen\n' +
+ '\n' +
+ '## Vix posse vestem\n' +
+ '\n' +
+ 'Nec deos robora visa pater toris remittit *crimina* utque, ora ego lacerae quae\n' +
+ 'laboris laturus silvas audax terrae. Qua fuisse patrio inlaesas [sine\n' +
+ 'seque](http://ambitvictore.org/), nondum et tamen annis, nec. Poscimur magnum,\n' +
+ 'Hesperium dedisti, ait ipse et fides terras scalas.\n' +
+ '\n' +
+ '- Quas superis satyri adloquitur natura hausimus\n' +
+ '- Dux suspicere siccare\n' +
+ '- Cape huc quid videor\n' +
+ '- Foret vivit concolor\n' +
+ '- Occupat morte oblectamina minuunt quaeque placidis nate\n' +
+ '- Non posset' +
+ '\n' +
+ 'Licet movitque dederat potest in sorores in sola pendere luce pro quod, sit.\n' +
+ 'Inpia ut in opibus flores uno quam quo multifidasque fera anhelitus retorsit.\n' +
+ 'Sustinui premebat puppe somnos. Dicit genu sic qualia excussit facunde parvae in\n' +
+ 'robur, Ianthe Interea. Superis victorque ponat puta cum: est enim.\n' +
+ '\n' +
+ '## Tacetve est in nullis Cerberus silvani luminibus\n' +
+ '\n' +
+ 'Divulsere *summissoque esse manes*; artus ausus conatoque utque: illo\n' +
+ 'Phaestiadas quod pascat et referentem, nec. In seris, iubebat iam nomina:\n' +
+ 'tergoque occidit ingenii.\n' +
+ '\n' +
+ ' mouseDdl(tablet_definition * phishing_icann_mamp);\n' +
+ ' vector += 20 + key_ram.source_isa(hard_tunneling_zone(w_wireless_page));\n' +
+ ' if (rate_client_direct) {\n' +
+ ' textXDpi += sql_cloud_class.sdk.speakers_wired_warm(pcZettabyteGis(\n' +
+ ' market_bezel, 1), 1);\n' +
+ ' tag_scraping = format_ppi;\n' +
+ ' }\n' +
+ '\n' +
+ 'Per quem, nec formosior qui cum Peliden me interea **ornatos**! Te facit\n' +
+ 'instimulat sequentia in flumina exilium te vulnere, sola. Coetum nec amnes.\n' +
+ 'Protinus nam Caras cava, *a* vocantem dicta inevitabile, nata nulla.\n' +
+ '\n' +
+ '## Piscem Iunoni maius\n' +
+ '\n' +
+ 'Prece fallere arduus, *ad Athamantis laticem* simillima in ante Temesesque opus!\n' +
+ 'Ausim quoslibet crede Tyria: Medusa [muneris Aeneaden\n' +
+ 'tutaque](http://cragon-aequoribus.io/) genitor fistula cogeris abstrahere nati,\n' +
+ 'relevare videri *non*.\n' +
+ '\n' +
+ '> Promissas ulterius senectae Desinet his ait pedum! Libet *sublime* vibrantia\n' +
+ '> si *dicta quod* pectora cupidine hastam dominoque.\n' +
+ '\n' +
+ 'Pedis hic, est bis quod, adhaeret et reditum. Fixa sic vel pugnare **forte est**\n' +
+ 'parte in quaerite generisque repugnat; de quod, creatos.';
+export const MarkdownContentCommonMark = () => (
+
+);
+
+export const MarkdownContentGithubFlavoredCommonMark = () => (
+
+);
diff --git a/packages/core/src/components/MarkdownContent/MarkdownContent.test.tsx b/packages/core/src/components/MarkdownContent/MarkdownContent.test.tsx
new file mode 100644
index 0000000000..a96525a3f6
--- /dev/null
+++ b/packages/core/src/components/MarkdownContent/MarkdownContent.test.tsx
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
+import { MarkdownContent } from './MarkdownContent';
+
+describe('', () => {
+ it('render MarkdownContent component with common mark', async () => {
+ const rendered = await renderWithEffects(
+ wrapInTestApp(
+ ,
+ ),
+ );
+ expect(rendered.getByText('H1', { selector: 'h1' })).toBeInTheDocument();
+ expect(rendered.getByText('H2', { selector: 'h2' })).toBeInTheDocument();
+ expect(rendered.getByText('H3', { selector: 'h3' })).toBeInTheDocument();
+ });
+
+ it('render MarkdownContent component with common mark github flavored', async () => {
+ const rendered = await renderWithEffects(
+ wrapInTestApp(
+ ,
+ ),
+ );
+ expect(
+ rendered.getByText('https://example.com', { selector: 'a' }),
+ ).toBeInTheDocument();
+ });
+});
diff --git a/packages/core/src/components/MarkdownContent/MarkdownContent.tsx b/packages/core/src/components/MarkdownContent/MarkdownContent.tsx
new file mode 100644
index 0000000000..1449c5b1be
--- /dev/null
+++ b/packages/core/src/components/MarkdownContent/MarkdownContent.tsx
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { makeStyles } from '@material-ui/core';
+import ReactMarkdown from 'react-markdown';
+import gfm from 'remark-gfm';
+import React from 'react';
+
+const useStyles = makeStyles(theme => ({
+ markdown: {
+ '& table': {
+ borderCollapse: 'collapse',
+ border: '1px solid #dfe2e5',
+ color: 'rgb(36, 41, 46)',
+ },
+ '& th, & td': {
+ border: '1px solid #dfe2e5',
+ padding: theme.spacing(1),
+ },
+ '& tr': {
+ backgroundColor: '#fff',
+ },
+ '& tr:nth-child(2n)': {
+ backgroundColor: '#f6f8fa',
+ },
+ '& pre': {
+ padding: '16px',
+ overflow: 'auto',
+ fontSize: '85%',
+ lineHeight: 1.45,
+ backgroundColor: '#f6f8fa',
+ borderRadius: '6px',
+ color: 'rgba(0, 0, 0, 0.87)',
+ },
+ '& a': {
+ color: '#2E77D0',
+ },
+ '& img': {
+ maxWidth: '100%',
+ },
+ },
+}));
+
+/**
+ * MarkdownContent. Renders markdown (CommonMark, optionally with [GFM](https://github.com/remarkjs/remark-gfm)) to formatted HTML.
+ */
+type Props = {
+ content: string;
+ enableGfm?: boolean;
+};
+
+export const MarkdownContent = ({ content, enableGfm = false }: Props) => {
+ const classes = useStyles();
+ return (
+
+ );
+};
diff --git a/packages/core/src/components/MarkdownContent/index.ts b/packages/core/src/components/MarkdownContent/index.ts
new file mode 100644
index 0000000000..7267ff191c
--- /dev/null
+++ b/packages/core/src/components/MarkdownContent/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { MarkdownContent } from './MarkdownContent';
diff --git a/packages/core/src/components/index.ts b/packages/core/src/components/index.ts
index 4f085ffd6a..40c4ef0c11 100644
--- a/packages/core/src/components/index.ts
+++ b/packages/core/src/components/index.ts
@@ -35,3 +35,4 @@ export * from './Tabs';
export * from './TrendLine';
export * from './WarningPanel';
export * from './EmptyState';
+export * from './MarkdownContent';