{
    "componentChunkName": "component---src-templates-blog-post-tsx",
    "path": "/blog/2022-02-14-component-library-backstage/",
    "result": {"data":{"blogPost":{"title":"Tutorial: How to use your company’s component library with Backstage","slug":"/blog/2022-02-14-component-library-backstage/","authorNodes":[{"name":"Taras Mankovski","slug":"/people/taras-mankovski/"}],"markdown":{"html":"<p>One of the first questions that a developer starting a Backstage project has to answer is how to make their developer portal match their company’s corporate style. There are several ways of doing this, but I recommend using an approach that will allow developers to use as much of the Backstage UI as possible so that everyone gets the most value from Backstage. The further the developer portal is from the beaten path, the fewer Backstage elements the development team will have access to.</p>\n<p>The approach that retains the most value from Backstage is using a <a href=\"https://backstage.io/docs/getting-started/app-custom-theme#example-of-a-custom-theme\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">custom Material UI theme</a> which allows developers to use <strong>all</strong> of the existing Backstage plugins. If specific components need to be modified, there is the option of <a href=\"https://backstage.io/docs/getting-started/app-custom-theme#overriding-backstage-and-material-ui-components-styles\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">overriding Backstage and Material UI styles</a>. Admittedly, this approach can take a fair bit of tweaking and can be somewhat tedious, but will likely result in being able to use all of the existing and future Backstage plugins.</p>\n<p>If using the UI components provided by Backstage plugins is less important than using your internal component library, there are still good reasons to maintain access to their data. In addition to Material UI components, the Backstage frontend framework provides a data fetching API for retrieving data from the backend. Even if you’re not using the UI components of Backstage plugins, you can continue to benefit from them by leveraging their data API.</p>\n<p>In this tutorial, I will illustrate how to replace Material UI with the <a href=\"https://developer.microsoft.com/en-us/fluentui#/controls/web\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Fluent UI</a> component library, then use the Catalog Client API and FluentUI’s DetailList to display a list of catalog entities from Backstage's backend. Let’s get started!</p>\n<h2 id=\"create-a-backstage-app\" style=\"position:relative;\"><a href=\"#create-a-backstage-app\" aria-label=\"create a backstage app permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create a Backstage App</h2>\n<p>If you don’t already have an instance of a Backstage app, create one by running:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npx @backstage/create-app</code></pre></div>\n<p>For this tutorial, you can select <code class=\"language-text\">SQLite</code> as your backend database as it will save you the hassle of having to run a local instance of <code class=\"language-text\">Postgres</code>.</p>\n<h2 id=\"clean-up-your-app\" style=\"position:relative;\"><a href=\"#clean-up-your-app\" aria-label=\"clean up your app permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Clean up your app</h2>\n<p>Before we start adding our theme, we need to do a bit of clean up. Since we’re not going to be using Material UI, there is no need to keep its dependencies. We’ll start by removing those packages:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">yarn workspace app remove @backstage/theme @material-ui/core @material-ui/icons</code></pre></div>\n<p>You can also go ahead and delete everything in the <code class=\"language-text\">packages/app/src/components/</code> directory and create a simple <code class=\"language-text\">Home</code> component that will be our new Home page (without all the Backstage frontend elements):</p>\n<div class=\"gatsby-highlight\" data-language=\"tsx\"><pre class=\"language-tsx\"><code class=\"language-tsx\"><span class=\"token comment\">// packages/app/src/components/Home.tsx</span>\n\n<span class=\"token keyword\">import</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Home</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Home</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Next, you need to remove all the routes and plugins and add the new Home component to your app. There is a lot to remove so I’ll show you what your <code class=\"language-text\">App.tsx</code> in <code class=\"language-text\">./packages/app/src/</code> should look like:</p>\n<div class=\"gatsby-highlight\" data-language=\"tsx\"><pre class=\"language-tsx\"><code class=\"language-tsx\"><span class=\"token keyword\">import</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Route <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-router'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> apis <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./apis'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createApp <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@backstage/app-defaults'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> FlatRoutes <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@backstage/core-app-api'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Home <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/Home'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> app <span class=\"token operator\">=</span> <span class=\"token function\">createApp</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  apis<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> AppProvider <span class=\"token operator\">=</span> app<span class=\"token punctuation\">.</span><span class=\"token function\">getProvider</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> AppRouter <span class=\"token operator\">=</span> app<span class=\"token punctuation\">.</span><span class=\"token function\">getRouter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> routes <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">FlatRoutes</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Route</span></span> <span class=\"token attr-name\">path</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">element</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Home</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\">\n  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">FlatRoutes</span></span><span class=\"token punctuation\">></span></span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">AppProvider</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">AppRouter</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n      </span><span class=\"token punctuation\">{</span>routes<span class=\"token punctuation\">}</span><span class=\"token plain-text\">\n    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">AppRouter</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">\n  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">AppProvider</span></span><span class=\"token punctuation\">></span></span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App<span class=\"token punctuation\">;</span></code></pre></div>\n<h2 id=\"install-your-component-library\" style=\"position:relative;\"><a href=\"#install-your-component-library\" aria-label=\"install your component library permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Install your component library</h2>\n<p>Next, install the <code class=\"language-text\">@fluentui/react</code> component library to your frontend by running:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">yarn workspace app add @fluentui/react</code></pre></div>\n<p>This will allow you to use components from the library in the frontend application. We can now modify <code class=\"language-text\">Home.tsx</code> to display a component from <code class=\"language-text\">@fluentui/react</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\">import React from 'react';\n<span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import { PrimaryButton } from '@fluentui/react';\n</span>\nexport const Home = () => {\n<span class=\"token deleted-sign deleted\"><span class=\"token prefix deleted\">-</span>  return &lt;p>Home&lt;/p>;\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>  return &lt;PrimaryButton>Press me!&lt;/PrimaryButton>;\n</span>}</code></pre></div>\n<p>If you run <code class=\"language-text\">yarn start</code>, you should be able to see a button with the default Fluent UI style that says “Press me!”.</p>\n<h2 id=\"change-the-theme-provider\" style=\"position:relative;\"><a href=\"#change-the-theme-provider\" aria-label=\"change the theme provider permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Change the theme provider</h2>\n<p>By default, Backstage’s <code class=\"language-text\">createApp</code> uses a Material UI theme provider that adds Backstage’s specific styles. We want to replace this default theme provider with the one from your component library. To do this, you need to modify <code class=\"language-text\">App.tsx</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\"><span class=\"token deleted-sign deleted\"><span class=\"token prefix deleted\">-</span> import React from 'react';\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import React, { ComponentType } from 'react';\n<span class=\"token prefix inserted\">+</span> import { ThemeProvider, PartialTheme } from '@fluentui/react';\n</span>...\n<span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> const myTheme: PartialTheme = {\n<span class=\"token prefix inserted\">+</span>   semanticColors: {\n<span class=\"token prefix inserted\">+</span>     primaryButtonBackground: 'red',\n<span class=\"token prefix inserted\">+</span>     primaryButtonText: 'white',\n<span class=\"token prefix inserted\">+</span>   },\n<span class=\"token prefix inserted\">+</span> }\n<span class=\"token prefix inserted\">+</span> \n<span class=\"token prefix inserted\">+</span> const MyThemeProvider: ComponentType&lt;{}> = ({ children }) => {\n<span class=\"token prefix inserted\">+</span>   return (&lt;ThemeProvider theme={myTheme}>{children}&lt;/ThemeProvider>);\n<span class=\"token prefix inserted\">+</span> }\n<span class=\"token prefix inserted\">+</span>\n</span>const app = createApp({\n<span class=\"token unchanged\"><span class=\"token prefix unchanged\"> </span> apis,\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>  components: {\n<span class=\"token prefix inserted\">+</span>    ThemeProvider: MyThemeProvider,\n<span class=\"token prefix inserted\">+</span>  }\n</span>})</code></pre></div>\n<p>Once you make these changes, your UI is now using your component library. Be aware that if you render any components that come with Backstage, they will not work because the default Backstage theme provider will be missing.</p>\n<h2 id=\"use-backstage-catalog-api-to-fetch-data-and-display-it-in-a-table\" style=\"position:relative;\"><a href=\"#use-backstage-catalog-api-to-fetch-data-and-display-it-in-a-table\" aria-label=\"use backstage catalog api to fetch data and display it in a table permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Use Backstage Catalog API to fetch data and display it in a table</h2>\n<p>The work that you did so far was to add a new theme to the Backstage component. You did this by modifying the frontend app. Other teams sometimes take a different approach where they create an entirely new Create React App project and import <em>that</em> to their Backstage app. Starting a new project may seem appealing, but in practice you’d be giving up more features than you realize. One of the most important lost features is the ability to call data APIs provided by the Backstage framework.</p>\n<p>If your connection to the backend is intact, you can still use the data fetching API provided by Backstage. The Backstage UI components you deleted earlier already had data fetching implemented, which means the <code class=\"language-text\">Home</code> component you created is missing that functionality. I will now show how to use the data API to fetch data from the Backstage backend and display it in a <code class=\"language-text\">DetailList</code> component.</p>\n<h2 id=\"make-catalog-api-available-in-your-application\" style=\"position:relative;\"><a href=\"#make-catalog-api-available-in-your-application\" aria-label=\"make catalog api available in your application permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Make catalog API available in your application</h2>\n<p>First, install <code class=\"language-text\">@backstage/catalog-client</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">yarn workspace app add @backstage/catalog-client</code></pre></div>\n<p>You can make the Catalog API available in your application by adding an API factory to the <code class=\"language-text\">apis.ts</code> file in your <code class=\"language-text\">package/app/src/</code> directory:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\"><span class=\"token unchanged\"><span class=\"token prefix unchanged\"> </span> createApiFactory,\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>   discoveryApiRef\n</span>} from '@backstage/core-plugin-api';\n<span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import { catalogApiRef } from '@backstage/plugin-catalog-react';\n<span class=\"token prefix inserted\">+</span> import { CatalogClient } from '@backstage/catalog-client';\n</span>\nexport const apis: AnyApiFactory[] = [\n<span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>   createApiFactory({\n<span class=\"token prefix inserted\">+</span>     api: catalogApiRef,\n<span class=\"token prefix inserted\">+</span>     deps: { discoveryApi: discoveryApiRef },\n<span class=\"token prefix inserted\">+</span>     factory: ({ discoveryApi }) => new CatalogClient({ discoveryApi })\n<span class=\"token prefix inserted\">+</span>   }),\n</span><span class=\"token unchanged\"><span class=\"token prefix unchanged\"> </span> createApiFactory({</span></code></pre></div>\n<p>Let’s unpack what you see above. You will use the Catalog API reference (which comes from <code class=\"language-text\">@backstage/plugin-catalog-react</code>) to look up the API in your components when using the <code class=\"language-text\">useApi</code> hook. The <code class=\"language-text\">AnyApiFactory</code> factory controls how the Catalog Client is created. <code class=\"language-text\">CatalogClient</code> needs <code class=\"language-text\">DiscoveryApiRef</code>, which provides the factory access to the <code class=\"language-text\">DiscoveryApi</code>. The DiscoveryApi is used to find the URL where the Backstage Catalog API can be found. This piping will make it easy to call the API in future steps.</p>\n<h2 id=\"use-useapi-hook-to-get-the-catalogapi\" style=\"position:relative;\"><a href=\"#use-useapi-hook-to-get-the-catalogapi\" aria-label=\"use useapi hook to get the catalogapi permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Use <code class=\"language-text\">useApi</code> hook to get the CatalogApi</h2>\n<p>Let’s get rid of the <code class=\"language-text\">PrimaryButton</code> from earlier and make the following additional changes in your <code class=\"language-text\">Home</code> component:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\"><span class=\"token deleted-sign deleted\"><span class=\"token prefix deleted\">-</span> import { PrimaryButton } from '@fluentui/react';\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import { catalogApiRef } from '@backstage/plugin-catalog-react';\n<span class=\"token prefix inserted\">+</span> import { useApi } from '@backstage/core-plugin-api';\n</span>\nexport const Home = () => {\n<span class=\"token deleted-sign deleted\"><span class=\"token prefix deleted\">-</span>   return &lt;PrimaryButton>Press me!&lt;/PrimaryButton>\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>   const catalogApi = useApi(catalogApiRef);\n</span>}</code></pre></div>\n<p>This provides your component with access to reference to the Catalog API. As a result, we can call this API to retrieve data from the Catalog API.</p>\n<h2 id=\"use-useasync-hook-to-call-the-catalogapi\" style=\"position:relative;\"><a href=\"#use-useasync-hook-to-call-the-catalogapi\" aria-label=\"use useasync hook to call the catalogapi permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Use <code class=\"language-text\">useAsync</code> hook to call the CatalogApi</h2>\n<p>To call the CatalogApi, we need to call <code class=\"language-text\">catalogApi.getEntities</code> function. This function needs to be called with our component renders. We can use the <code class=\"language-text\">useAsync</code> hook to call <code class=\"language-text\">catalogApi.getEntities</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\"><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import useAsync from 'react-use/lib/useAsync';\n</span>\nexport const Home = () => {\n<span class=\"token unchanged\"><span class=\"token prefix unchanged\"> </span> const catalogApi = useApi(catalogApiRef);\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>   const {\n<span class=\"token prefix inserted\">+</span>     value = { items: [] },\n<span class=\"token prefix inserted\">+</span>     // loading,\n<span class=\"token prefix inserted\">+</span>     // error,\n<span class=\"token prefix inserted\">+</span>   } = useAsync(() =>\n<span class=\"token prefix inserted\">+</span>     catalogApi.getEntities({\n<span class=\"token prefix inserted\">+</span>       filter: {\n<span class=\"token prefix inserted\">+</span>         kind: 'Component',\n<span class=\"token prefix inserted\">+</span>       },\n<span class=\"token prefix inserted\">+</span>     }),\n<span class=\"token prefix inserted\">+</span>   );\n</span>}</code></pre></div>\n<p>We could implement the same thing with <code class=\"language-text\">useEffect</code> and <code class=\"language-text\">useState</code> but it’s a lot more work. <code class=\"language-text\">useAsync</code> automatically gives us <code class=\"language-text\">loading</code> and <code class=\"language-text\">error</code> values so we don’t need to handle those situations manually.</p>\n<h2 id=\"use-usememo-hook-to-convert-result-from-catalogapi-into-items-for-detailslist\" style=\"position:relative;\"><a href=\"#use-usememo-hook-to-convert-result-from-catalogapi-into-items-for-detailslist\" aria-label=\"use usememo hook to convert result from catalogapi into items for detailslist permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Use <code class=\"language-text\">useMemo</code> hook to convert result from CatalogApi into items for <code class=\"language-text\">DetailsList</code></h2>\n<p>FluentUI’s <code class=\"language-text\">DetailList</code> needs to convert results from the CatalogApi. The data needs to be in a specific format so that we can display it in the table:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\"><span class=\"token deleted-sign deleted\"><span class=\"token prefix deleted\">-</span> import React from 'react';\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import React, { useMemo } from 'react';\n</span>\nexport const Home = () => {\n<span class=\"token unchanged\"><span class=\"token prefix unchanged\"> </span> ...\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>   const items = useMemo(\n<span class=\"token prefix inserted\">+</span>     () =>\n<span class=\"token prefix inserted\">+</span>       value.items.map(item => ({\n<span class=\"token prefix inserted\">+</span>         key: item.metadata.uid,\n<span class=\"token prefix inserted\">+</span>         name: item.metadata.name,\n<span class=\"token prefix inserted\">+</span>         description: item.metadata.description,\n<span class=\"token prefix inserted\">+</span>       })),\n<span class=\"token prefix inserted\">+</span>     [value],\n<span class=\"token prefix inserted\">+</span>   );\n</span>}</code></pre></div>\n<p><code class=\"language-text\">useMemo</code> allows us to covert the response from a CatalogApi response format to DetailList format and cache the result. The caching part is important because without it the list will re-render every time anything in that component changes.</p>\n<h2 id=\"render-detaillist-with-items\" style=\"position:relative;\"><a href=\"#render-detaillist-with-items\" aria-label=\"render detaillist with items permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Render <code class=\"language-text\">DetailList</code> with items</h2>\n<p>The final step is to import <code class=\"language-text\">DetailList</code> from <code class=\"language-text\">@fluentui/react</code> and render it. Making this last change should generate a list of items from the catalog using the Catalog API and rendered in the components from FluentUI library:</p>\n<div class=\"gatsby-highlight\" data-language=\"diff\"><pre class=\"language-diff\"><code class=\"language-diff\"><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> import { DetailsList } from '@fluentui/react';\n</span>\nexport const Home = () => {\n<span class=\"token unchanged\"><span class=\"token prefix unchanged\"> </span> ...\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span>   return &lt;DetailsList items={items} />;\n</span>}</code></pre></div>\n<p>To check to make sure these new changes are working properly, run <code class=\"language-text\">yarn dev</code> (you’ll need the backend to be running too).</p>\n<p>This whole process is a bit involved but doing it this way saves you a lot of trouble in the long run by allowing you to use the data fetching APIs that come with Backstage plugins.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>In this tutorial, I showed you how to clean up the frontend application in preparation for using your own component library, install a component library other than Material UI, override the theme provider to use your component library’s theme provider, and use Backstage’s data fetching API provided by the Catalog API plugin.</p>\n<p>This is the “right” way to use your company’s component library because it allows you to use it without completely eliminating all of the benefits that the Backstage framework provides in the frontend application. You might not be able to use the components that Backstage plugins provide because they are tied to Material UI, but you can still use the data fetching APIs that idiomatic Backstage plugins include.</p>\n<p>I hope you enjoyed this tutorial and learned something about Backstage. You can find me on <a href=\"https://twitter.com/tarasm\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Twitter</a>, <a href=\"https://github.com/taras\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">GitHub</a>, or via email - <a href=\"mailto:tarasm@frontside.com\">tarasm@frontside.com</a>. All of the code from this tutorial can be found in <a href=\"https://github.com/taras/backstage-custom-frontend\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://github.com/taras/backstage-custom-frontend</a></p>","frontmatter":{"date":"February 14, 2022","description":"In this tutorial, Taras will show you how to replace Material UI for your component library in Backstage without losing access to its API.","tags":["backstage"],"img":{"childImageSharp":{"fixed":{"src":"/static/20b208f9f906897d36d20a0ea7065e58/31987/2022-backstage-components.png"}}}}}}},"pageContext":{"id":"8ed19c50-26ed-5f23-9fec-37841ef77523"}},
    "staticQueryHashes": ["1241260443"]}