diff --git a/docs/conf/user-interface/icons.md b/docs/conf/user-interface/icons.md new file mode 100644 index 0000000000..44b8782430 --- /dev/null +++ b/docs/conf/user-interface/icons.md @@ -0,0 +1,124 @@ +--- +id: icons +title: Customizing Icons +sidebar_label: Icons +description: Customizing Icons +--- + +So far you've seen how to create your own theme and add your own logo, in the following sections you'll be shown how to override the existing icons and how to add more icons + +## Custom Icons + +You can also customize the Project's _default_ icons. + +You can change the following [icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx). + +### Requirements + +- Files in `.svg` format +- React components created for the icons + +### Create React Component + +In your front-end application, locate the `src` folder. We suggest creating the `assets/icons` directory and `CustomIcons.tsx` file. + +```tsx title="customIcons.tsx" +import { SvgIcon, SvgIconProps } from '@material-ui/core'; + +export const ExampleIcon = (props: SvgIconProps) => ( + + + +); +``` + +### Using the custom icon + +Supply your custom icon in `packages/app/src/App.tsx` + +```tsx title="packages/app/src/App.tsx" +/* highlight-add-next-line */ +import { ExampleIcon } from './assets/icons/CustomIcons' + + +const app = createApp({ + apis, + components: { + {/* ... */} + }, + themes: [ + {/* ... */} + ], + /* highlight-add-start */ + icons: { + github: ExampleIcon, + }, + /* highlight-add-end */ + bindRoutes({ bind }) { + {/* ... */} + } +}) +``` + +## Adding Icons + +You can add more icons, if the [default icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx) do not fit your needs, so that they can be used in other places like for Links in your entities. For this example we'll be using icons from[Material UI](https://v4.mui.com/components/material-icons/) and specifically the `AlarmIcon`. Here's how to do that: + +1. First you will want to open your `App.tsx` in `/packages/app/src` +2. Then you want to import your icon, add this to the rest of your imports: `import AlarmIcon from '@material-ui/icons/Alarm';` +3. Next you want to add the icon like this to your `createApp`: + + ```tsx title="packages/app/src/App.tsx" + const app = createApp({ + apis: ..., + plugins: ..., + /* highlight-add-start */ + icons: { + alert: AlarmIcon, + }, + /* highlight-add-end */ + themes: ..., + components: ..., + }); + ``` + +4. Now we can reference `alert` for our icon in our entity links like this: + + ```yaml + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: artist-lookup + description: Artist Lookup + links: + - url: https://example.com/alert + title: Alerts + icon: alert + ``` + + And this is the result: + + ![Example Link with Alert icon](../../assets/getting-started/add-icons-links-example.png) + + Another way you can use these icons is from the `AppContext` like this: + + ```ts + import { useApp } from '@backstage/core-plugin-api'; + + const app = useApp(); + const alertIcon = app.getSystemIcon('alert'); + ``` + + You might want to use this method if you have an icon you want to use in several locations. + +:::note Note + +If the icon is not available as one of the default icons or one you've added then it will fall back to Material UI's `LanguageIcon` + +::: diff --git a/docs/conf/user-interface/index.md b/docs/conf/user-interface/index.md new file mode 100644 index 0000000000..9be726d2dc --- /dev/null +++ b/docs/conf/user-interface/index.md @@ -0,0 +1,471 @@ +--- +id: index +title: Customizing Your App's UI +sidebar_label: Introduction +description: Learn how to customize the look and feel of your Backstage app, including theming and branding options. +--- + +Backstage offers built-in support for both light and dark themes, making it easy to get started with a professional look and feel. But many teams want to go further—tailoring the interface to reflect their organization’s unique brand, identity, and experience. + +This section explores the different ways you can customize the appearance of your Backstage instance. You'll learn how the theming system is structured today, how to work with the two coexisting UI systems, and how to define themes that align with your visual language. + +## Theming architecture overview + +Backstage currently supports two parallel UI systems. The original theming and component model is built on Material UI (MUI), a popular React-based framework. More recently, Backstage introduced Backstage UI (BUI), a custom-designed, CSS-first system developed to meet the platform’s evolving needs. Both systems are supported today, with many parts of the ecosystem still using MUI while new components adopt BUI. + +
+
+

MUI (Legacy)

+ +
+
+

Backstage UI (New)

+ +
+
+ +:::info +We recognize that maintaining two separate theming systems is not ideal. Because of the fundamental architectural differences between MUI and Backstage UI, it can be challenging to automate theme updates or know exactly which theme to modify for a given component. Our recommendation is to inspect the component’s code and check its class names: if you see a class name starting with `bui`, you should use the Backstage UI theming approach to style it. +::: + +## Creating custom themes + +During the transition to Backstage UI, you will need to maintain themes in two places: some components and plugins still rely on MUI, while others use Backstage UI. At this time, there is no automated solution to generate MUI themes from your Backstage UI theme, so you will need to manage both separately until the migration is complete. + +```tsx title="packages/app/src/App.tsx" +/* highlight-add-start */ +import { lightTheme, darkTheme } from './themes'; // MUI themes +import './styles.css'; // Backstage UI (BUI) theme +/* highlight-add-end */ + +const app = createApp({ + apis, + components, + /* highlight-add-start */ + themes: [ + { + id: 'light', + title: 'Light theme', + variant: 'light', + icon: , + Provider: ({ children }) => ( + + ), + }, + { + id: 'dark', + title: 'Dark theme', + variant: 'dark', + icon: , + Provider: ({ children }) => ( + + ), + }, + ], + /* highlight-add-end */ +}); +``` + +| Name | Description | +| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | Each theme has a unique `id` | +| `title` | This will be shown in the settings page to select the right theme. | +| `variant` | This can be either `light` or `dark`. This is also refered as `mode`. On the `body` of your app we are inserting a data attribute to set the theme based on this value `data-theme-mode="light"`. | +| `icon` | This will be shown in the settings page as a visual element to complement the title. | +| `Provider` | This is needed to set the legacy theme with MUI only. This will be become redundant later on when we fully replace with BUI but for now you need to have it for MUI to work. BUI is based on CSS and don't rely on any global providers. | + +:::note +Your list of custom themes overrides the default themes. If you still want to use the default themes, they are exported as `themes.light` and `themes.dark` from [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). Be sure to provide both `light` and `dark` modes so users can choose their preference. +::: + +## Create a theme for Backstage UI (New) + +Backstage UI is built entirely using CSS. By default we are providing a default theme that include all our core CSS variables and component styles. To start customising Backstage UI to match your brand you need to create a new CSS file and import it directly in `packages/app/src/App.tsx`. All styles declared in this file will override the default styles. As your file grow you can organise it the way you want or even import multiple files. + +Backstage UI is using light by default under `:root` but you can target it more specifically using the data attribute for mode + +```css title="packages/app/src/styles.css" +:root { + /* Use :root to set styles for both light and dark themes */ + .bui-Button { + background-color: #000; + color: #fff; + } +} + +[data-theme-mode='light'] { + /* Light theme specific styles */ +  --bui-bg: #f8f8f8; + --bui-fg-primary: #000; +} + +[data-theme-mode='dark'] { + /* Dark theme specific styles */ +  --bui-bg: #333333; + --bui-fg-primary: #fff; +} +``` + +### Available tokens + +### Component class names + +### Custom font + +## Create a theme for MUI (Legacy) + +To customize the appearance of your Backstage app using the legacy MUI theming system, you can define your own theme by extending the built-in light or dark themes. This is done using the createUnifiedTheme utility provided by the [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme) package. This function allows you to override key aspects of the theme—such as color palette, typography, spacing, and shape—while preserving Backstage’s base configuration and component compatibility. + +The example below shows how to create a new theme based on the default light theme: + +```ts title="packages/app/src/themes.ts" +import { + createBaseThemeOptions, + createUnifiedTheme, + palettes, +} from '@backstage/theme'; + +export const lightTheme = createUnifiedTheme({ + ...createBaseThemeOptions({ + palette: palettes.light, + }), + fontFamily: 'Comic Sans MS', + defaultPageTheme: 'home', +}); + +export const darkTheme = createUnifiedTheme({ + ...createBaseThemeOptions({ + palette: palettes.dark, + }), + fontFamily: 'Comic Sans MS', + defaultPageTheme: 'home', +}); +``` + +You can also create a theme from scratch that matches the `BackstageTheme` type exported by [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). See the +[Material UI docs on theming](https://material-ui.com/customization/theming/) for more information about how that can be done. + +
+ Example of a custom MUI theme + +For a more complete example of a custom theme including Backstage and Material UI component overrides, see the [Aperture theme](https://github.com/backstage/demo/blob/master/packages/app/src/theme/aperture.ts) from the [Backstage demo site](https://demo.backstage.io). + +```ts title="packages/app/src/themes.ts" +import { + createBaseThemeOptions, + createUnifiedTheme, + genPageTheme, + palettes, + shapes, +} from '@backstage/theme'; + +export const myTheme = createUnifiedTheme({ + ...createBaseThemeOptions({ + palette: { + ...palettes.light, + primary: { + main: '#343b58', + }, + secondary: { + main: '#565a6e', + }, + error: { + main: '#8c4351', + }, + warning: { + main: '#8f5e15', + }, + info: { + main: '#34548a', + }, + success: { + main: '#485e30', + }, + background: { + default: '#d5d6db', + paper: '#d5d6db', + }, + banner: { + info: '#34548a', + error: '#8c4351', + text: '#343b58', + link: '#565a6e', + }, + errorBackground: '#8c4351', + warningBackground: '#8f5e15', + infoBackground: '#343b58', + navigation: { + background: '#343b58', + indicator: '#8f5e15', + color: '#d5d6db', + selectedColor: '#ffffff', + }, + }, + }), + defaultPageTheme: 'home', + fontFamily: 'Comic Sans MS', + /* below drives the header colors */ + pageTheme: { + home: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), + documentation: genPageTheme({ + colors: ['#8c4351', '#343b58'], + shape: shapes.wave2, + }), + tool: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.round }), + service: genPageTheme({ + colors: ['#8c4351', '#343b58'], + shape: shapes.wave, + }), + website: genPageTheme({ + colors: ['#8c4351', '#343b58'], + shape: shapes.wave, + }), + library: genPageTheme({ + colors: ['#8c4351', '#343b58'], + shape: shapes.wave, + }), + other: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), + app: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), + apis: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), + }, +}); +``` + +
+ +
+ Custom Typography + +When creating a custom theme you can also customize various aspects of the default typography, here's an example using simplified theme: + +```ts title="packages/app/src/theme/myTheme.ts" +import { + createBaseThemeOptions, + createUnifiedTheme, + palettes, +} from '@backstage/theme'; + +export const myTheme = createUnifiedTheme({ + ...createBaseThemeOptions({ + palette: palettes.light, + typography: { + htmlFontSize: 16, + fontFamily: 'Arial, sans-serif', + h1: { + fontSize: 54, + fontWeight: 700, + marginBottom: 10, + }, + h2: { + fontSize: 40, + fontWeight: 700, + marginBottom: 8, + }, + h3: { + fontSize: 32, + fontWeight: 700, + marginBottom: 6, + }, + h4: { + fontWeight: 700, + fontSize: 28, + marginBottom: 6, + }, + h5: { + fontWeight: 700, + fontSize: 24, + marginBottom: 4, + }, + h6: { + fontWeight: 700, + fontSize: 20, + marginBottom: 2, + }, + }, + defaultPageTheme: 'home', + }), +}); +``` + +If you wanted to only override a sub-set of the typography setting, for example just `h1` then you would do this: + +```ts title="packages/app/src/theme/myTheme.ts" +import { + createBaseThemeOptions, + createUnifiedTheme, + defaultTypography, + palettes, +} from '@backstage/theme'; + +export const myTheme = createUnifiedTheme({ + ...createBaseThemeOptions({ + palette: palettes.light, + typography: { + ...defaultTypography, + htmlFontSize: 16, + fontFamily: 'Roboto, sans-serif', + h1: { + fontSize: 72, + fontWeight: 700, + marginBottom: 10, + }, + }, + defaultPageTheme: 'home', + }), +}); +``` + +
+ +
+ Custom Fonts + +To add custom fonts, you first need to store the font so that it can be imported. We suggest creating the `assets/fonts` directory in your front-end application `src` folder. + +You can then declare the font style following the `@font-face` syntax from [Material UI Typography](https://mui.com/material-ui/customization/typography/). + +After that you can then utilize the `styleOverrides` of `MuiCssBaseline` under components to add a font to the `@font-face` array. + +```ts title="packages/app/src/theme/myTheme.ts" +import MyCustomFont from '../assets/fonts/My-Custom-Font.woff2'; + +const myCustomFont = { + fontFamily: 'My-Custom-Font', + fontStyle: 'normal', + fontDisplay: 'swap', + fontWeight: 300, + src: ` + local('My-Custom-Font'), + url(${MyCustomFont}) format('woff2'), + `, +}; + +export const myTheme = createUnifiedTheme({ + fontFamily: 'My-Custom-Font', + palette: palettes.light, + components: { + MuiCssBaseline: { + styleOverrides: { + '@font-face': [myCustomFont], + }, + }, + }, +}); +``` + +If you want to utilize different or multiple fonts, then you can set the top level `fontFamily` to what you want for your body, and then override `fontFamily` in `typography` to control fonts for various headings. + +```ts title="packages/app/src/theme/myTheme.ts" +import MyCustomFont from '../assets/fonts/My-Custom-Font.woff2'; +import myAwesomeFont from '../assets/fonts/My-Awesome-Font.woff2'; + +const myCustomFont = { + fontFamily: 'My-Custom-Font', + fontStyle: 'normal', + fontDisplay: 'swap', + fontWeight: 300, + src: ` + local('My-Custom-Font'), + url(${MyCustomFont}) format('woff2'), + `, +}; + +const myAwesomeFont = { + fontFamily: 'My-Awesome-Font', + fontStyle: 'normal', + fontDisplay: 'swap', + fontWeight: 300, + src: ` + local('My-Awesome-Font'), + url(${myAwesomeFont}) format('woff2'), + `, +}; + +export const myTheme = createUnifiedTheme({ + fontFamily: 'My-Custom-Font', + components: { + MuiCssBaseline: { + styleOverrides: { + '@font-face': [myCustomFont, myAwesomeFont], + }, + }, + }, + ...createBaseThemeOptions({ + palette: palettes.light, + typography: { + ...defaultTypography, + htmlFontSize: 16, + fontFamily: 'My-Custom-Font', + h1: { + fontSize: 72, + fontWeight: 700, + marginBottom: 10, + fontFamily: 'My-Awesome-Font', + }, + }, + defaultPageTheme: 'home', + }), +}); +``` + +
+ +
+ Overriding Backstage and Material UI components styles + +When creating a custom theme you would be applying different values to component's CSS rules that use the theme object. For example, a Backstage component's styles might look like this: + +```tsx +const useStyles = makeStyles( + theme => ({ + header: { + padding: theme.spacing(3), + boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)', + backgroundImage: theme.page.backgroundImage, + }, + }), + { name: 'BackstageHeader' }, +); +``` + +Notice how the `padding` is getting its value from `theme.spacing`, that means that setting a value for spacing in your custom theme would affect this component padding property and the same goes for `backgroundImage` which uses `theme.page.backgroundImage`. However, the `boxShadow` property doesn't reference any value from the theme, that means that creating a custom theme wouldn't be enough to alter the `box-shadow` property or to add css rules that aren't already defined like a margin. For these cases you should also create an override. + +Here's how you would do that: + +```ts title="packages/app/src/theme/myTheme.ts" +import { + createBaseThemeOptions, + createUnifiedTheme, + palettes, +} from '@backstage/theme'; + +export const myTheme = createUnifiedTheme({ + ...createBaseThemeOptions({ + palette: palettes.light, + }), + fontFamily: 'Comic Sans MS', + defaultPageTheme: 'home', + components: { + BackstageHeader: { + styleOverrides: { + header: ({ theme }) => ({ + width: 'auto', + margin: '20px', + boxShadow: 'none', + borderBottom: `4px solid ${theme.palette.primary.main}`, + }), + }, + }, + }, +}); +``` + +
diff --git a/docs/conf/user-interface/logo.md b/docs/conf/user-interface/logo.md new file mode 100644 index 0000000000..35789d6330 --- /dev/null +++ b/docs/conf/user-interface/logo.md @@ -0,0 +1,25 @@ +--- +id: logo +title: Customizing Your Logo +sidebar_label: Logo +description: Learn how to customize your logo. +--- + +In addition to a custom theme, you can also customize the logo displayed at the far top left of the site. + +In your frontend app, locate `src/components/Root/` folder. You'll find two components: + +- `LogoFull.tsx` - A larger logo used when the Sidebar navigation is opened. +- `LogoIcon.tsx` - A smaller logo used when the Sidebar navigation is closed. + +To replace the images, you can simply replace the relevant code in those components with raw SVG definitions. + +You can also use another web image format such as PNG by importing it. To do this, place your new image into a new subdirectory such as `src/components/Root/logo/my-company-logo.png`, and then add this code: + +```tsx +import MyCustomLogoFull from './logo/my-company-logo.png'; + +const LogoFull = () => { + return ; +}; +``` diff --git a/docs/conf/user-interface/sidebar.md b/docs/conf/user-interface/sidebar.md new file mode 100644 index 0000000000..f66e6bd106 --- /dev/null +++ b/docs/conf/user-interface/sidebar.md @@ -0,0 +1,93 @@ +--- +id: sidebar +title: Customizing Your Sidebar +sidebar_label: Sidebar +description: Learn how to customize the look and feel of your Sidebar. +--- + +As you've seen there are many ways that you can customize your Backstage app. The following section will show you how you can customize the sidebar. + +## Sidebar Sub-menu + +For this example we'll show you how you can expand the sidebar with a sub-menu: + +1. Open the `Root.tsx` file located in `packages/app/src/components/Root` as this is where the sidebar code lives +2. Then we want to add the following import for `useApp`: + + ```tsx title="packages/app/src/components/Root/Root.tsx" + import { useApp } from '@backstage/core-plugin-api'; + ``` + +3. Then update the `@backstage/core-components` import like this: + + ```tsx title="packages/app/src/components/Root/Root.tsx" + import { + Sidebar, + sidebarConfig, + SidebarDivider, + SidebarGroup, + SidebarItem, + SidebarPage, + SidebarScrollWrapper, + SidebarSpace, + useSidebarOpenState, + Link, + /* highlight-add-start */ + GroupIcon, + SidebarSubmenu, + SidebarSubmenuItem, + /* highlight-add-end */ + } from '@backstage/core-components'; + ``` + +4. Finally replace `` with this: + + ```tsx title="packages/app/src/components/Root/Root.tsx" + + + + + + + + + + + + + + ``` + +When you startup your Backstage app and hover over the Home option on the sidebar you'll now see a nice sub-menu appear with links to the various Kinds in your Catalog. It would look like this: + +![Sidebar sub-menu example](./../../assets/getting-started/sidebar-submenu-example.png) + +You can see more ways to use this in the [Storybook Sidebar examples](https://backstage.io/storybook/?path=/story/layout-sidebar--sample-scalable-sidebar) diff --git a/docs/dls/component-design-guidelines.md b/docs/dls/component-design-guidelines.md index 35e2f987d2..17e9d1f11a 100644 --- a/docs/dls/component-design-guidelines.md +++ b/docs/dls/component-design-guidelines.md @@ -103,6 +103,8 @@ accessibility. [7]: https://v4.mui.com/components/cards/ [8]: https://v4.mui.com/customization/palette/#default-values [9]: https://v4.mui.com/customization/typography/ -[10]: https://backstage.io/docs/getting-started/app-custom-theme -[11]: https://backstage.io/docs/getting-started/app-custom-theme#overriding-backstage-and-material-ui-components-styles +[10]: https://backstage.io/docs/conf/user-interface + + + [12]: https://v4.mui.com/customization/default-theme/#explore diff --git a/docs/dls/design.md b/docs/dls/design.md index 7e2ae90528..e988d1032f 100644 --- a/docs/dls/design.md +++ b/docs/dls/design.md @@ -127,7 +127,7 @@ your own plugin for Backstage. **[Discord](https://discord.gg/backstage-687207715902193673)** - all design questions should be directed to the _#design_ channel. -**[Customize Backstage's look and feel](https://backstage.io/docs/getting-started/app-custom-theme)** - +**[Customizing Your App's UI](https://backstage.io/docs/conf/user-interface)** - How to customize the look and feel of your Backstage instance by extending the theme. diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index 7055db1138..f0823ac47e 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -116,7 +116,7 @@ indexBuilder.addCollator({ The default highlighting styling for matched terms in search results is your browsers default styles for the `` HTML tag. If you want to customize how highlighted terms look you can follow Backstage's guide on how to -[Customize the look-and-feel of your App](https://backstage.io/docs/getting-started/app-custom-theme) +[Customizing Your App's UI](https://backstage.io/docs/conf/user-interface) to create an override with your preferred styling. For example, using the new MUI V4+V5 unified theming method, the following will result diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md deleted file mode 100644 index 38f2fd4c98..0000000000 --- a/docs/getting-started/app-custom-theme.md +++ /dev/null @@ -1,613 +0,0 @@ ---- -id: app-custom-theme -title: Customize the look-and-feel of your App -description: Documentation on Customizing look and feel of the App ---- - -Backstage ships with a default theme with a light and dark mode variant. The themes are provided as a part of the [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme) package, which also includes utilities for customizing the default theme, or creating completely new themes. - -## Creating a Custom Theme - -The easiest way to create a new theme is to use the `createUnifiedTheme` function exported by the [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme) package. You can use it to override some basic parameters of the default theme such as the color palette and font. - -For example, you can create a new theme based on the default light theme like this: - -```ts title="packages/app/src/theme/myTheme.ts" -import { - createBaseThemeOptions, - createUnifiedTheme, - palettes, -} from '@backstage/theme'; - -export const myTheme = createUnifiedTheme({ - ...createBaseThemeOptions({ - palette: palettes.light, - }), - fontFamily: 'Comic Sans MS', - defaultPageTheme: 'home', -}); -``` - -:::note Note - -we recommend creating a `theme` folder in `packages/app/src` to place your theme file to keep things nicely organized. - -::: - -You can also create a theme from scratch that matches the `BackstageTheme` type exported by [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). See the -[Material UI docs on theming](https://material-ui.com/customization/theming/) for more information about how that can be done. - -## Using your Custom Theme - -To add a custom theme to your Backstage app, you pass it as configuration to `createApp`. - -For example, adding the theme that we created in the previous section can be done like this: - -```tsx title="packages/app/src/App.tsx" -import { createApp } from '@backstage/app-defaults'; -import { ThemeProvider } from '@material-ui/core/styles'; -import CssBaseline from '@material-ui/core/CssBaseline'; -import LightIcon from '@material-ui/icons/WbSunny'; -import { UnifiedThemeProvider} from '@backstage/theme'; -import { myTheme } from './themes/myTheme'; - -const app = createApp({ - apis: ..., - plugins: ..., - themes: [{ - id: 'my-theme', - title: 'My Custom Theme', - variant: 'light', - icon: , - Provider: ({ children }) => ( - - ), - }] -}) -``` - -Note that your list of custom themes overrides the default themes. If you still want to use the default themes, they are exported as `themes.light` and `themes.dark` from [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme). - -## Example of a custom theme - -```ts title="packages/app/src/theme/myTheme.ts" -import { - createBaseThemeOptions, - createUnifiedTheme, - genPageTheme, - palettes, - shapes, -} from '@backstage/theme'; - -export const myTheme = createUnifiedTheme({ - ...createBaseThemeOptions({ - palette: { - ...palettes.light, - primary: { - main: '#343b58', - }, - secondary: { - main: '#565a6e', - }, - error: { - main: '#8c4351', - }, - warning: { - main: '#8f5e15', - }, - info: { - main: '#34548a', - }, - success: { - main: '#485e30', - }, - background: { - default: '#d5d6db', - paper: '#d5d6db', - }, - banner: { - info: '#34548a', - error: '#8c4351', - text: '#343b58', - link: '#565a6e', - }, - errorBackground: '#8c4351', - warningBackground: '#8f5e15', - infoBackground: '#343b58', - navigation: { - background: '#343b58', - indicator: '#8f5e15', - color: '#d5d6db', - selectedColor: '#ffffff', - }, - }, - }), - defaultPageTheme: 'home', - fontFamily: 'Comic Sans MS', - /* below drives the header colors */ - pageTheme: { - home: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), - documentation: genPageTheme({ - colors: ['#8c4351', '#343b58'], - shape: shapes.wave2, - }), - tool: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.round }), - service: genPageTheme({ - colors: ['#8c4351', '#343b58'], - shape: shapes.wave, - }), - website: genPageTheme({ - colors: ['#8c4351', '#343b58'], - shape: shapes.wave, - }), - library: genPageTheme({ - colors: ['#8c4351', '#343b58'], - shape: shapes.wave, - }), - other: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), - app: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), - apis: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }), - }, -}); -``` - -For a more complete example of a custom theme including Backstage and Material UI component overrides, see the [Aperture theme](https://github.com/backstage/demo/blob/master/packages/app/src/theme/aperture.ts) from the [Backstage demo site](https://demo.backstage.io). - -## Custom Typography - -When creating a custom theme you can also customize various aspects of the default typography, here's an example using simplified theme: - -```ts title="packages/app/src/theme/myTheme.ts" -import { - createBaseThemeOptions, - createUnifiedTheme, - palettes, -} from '@backstage/theme'; - -export const myTheme = createUnifiedTheme({ - ...createBaseThemeOptions({ - palette: palettes.light, - typography: { - htmlFontSize: 16, - fontFamily: 'Arial, sans-serif', - h1: { - fontSize: 54, - fontWeight: 700, - marginBottom: 10, - }, - h2: { - fontSize: 40, - fontWeight: 700, - marginBottom: 8, - }, - h3: { - fontSize: 32, - fontWeight: 700, - marginBottom: 6, - }, - h4: { - fontWeight: 700, - fontSize: 28, - marginBottom: 6, - }, - h5: { - fontWeight: 700, - fontSize: 24, - marginBottom: 4, - }, - h6: { - fontWeight: 700, - fontSize: 20, - marginBottom: 2, - }, - }, - defaultPageTheme: 'home', - }), -}); -``` - -If you wanted to only override a sub-set of the typography setting, for example just `h1` then you would do this: - -```ts title="packages/app/src/theme/myTheme.ts" -import { - createBaseThemeOptions, - createUnifiedTheme, - defaultTypography, - palettes, -} from '@backstage/theme'; - -export const myTheme = createUnifiedTheme({ - ...createBaseThemeOptions({ - palette: palettes.light, - typography: { - ...defaultTypography, - htmlFontSize: 16, - fontFamily: 'Roboto, sans-serif', - h1: { - fontSize: 72, - fontWeight: 700, - marginBottom: 10, - }, - }, - defaultPageTheme: 'home', - }), -}); -``` - -## Custom Fonts - -To add custom fonts, you first need to store the font so that it can be imported. We suggest creating the `assets/fonts` directory in your front-end application `src` folder. - -You can then declare the font style following the `@font-face` syntax from [Material UI Typography](https://mui.com/material-ui/customization/typography/). - -After that you can then utilize the `styleOverrides` of `MuiCssBaseline` under components to add a font to the `@font-face` array. - -```ts title="packages/app/src/theme/myTheme.ts" -import MyCustomFont from '../assets/fonts/My-Custom-Font.woff2'; - -const myCustomFont = { - fontFamily: 'My-Custom-Font', - fontStyle: 'normal', - fontDisplay: 'swap', - fontWeight: 300, - src: ` - local('My-Custom-Font'), - url(${MyCustomFont}) format('woff2'), - `, -}; - -export const myTheme = createUnifiedTheme({ - fontFamily: 'My-Custom-Font', - palette: palettes.light, - components: { - MuiCssBaseline: { - styleOverrides: { - '@font-face': [myCustomFont], - }, - }, - }, -}); -``` - -If you want to utilize different or multiple fonts, then you can set the top level `fontFamily` to what you want for your body, and then override `fontFamily` in `typography` to control fonts for various headings. - -```ts title="packages/app/src/theme/myTheme.ts" -import MyCustomFont from '../assets/fonts/My-Custom-Font.woff2'; -import myAwesomeFont from '../assets/fonts/My-Awesome-Font.woff2'; - -const myCustomFont = { - fontFamily: 'My-Custom-Font', - fontStyle: 'normal', - fontDisplay: 'swap', - fontWeight: 300, - src: ` - local('My-Custom-Font'), - url(${MyCustomFont}) format('woff2'), - `, -}; - -const myAwesomeFont = { - fontFamily: 'My-Awesome-Font', - fontStyle: 'normal', - fontDisplay: 'swap', - fontWeight: 300, - src: ` - local('My-Awesome-Font'), - url(${myAwesomeFont}) format('woff2'), - `, -}; - -export const myTheme = createUnifiedTheme({ - fontFamily: 'My-Custom-Font', - components: { - MuiCssBaseline: { - styleOverrides: { - '@font-face': [myCustomFont, myAwesomeFont], - }, - }, - }, - ...createBaseThemeOptions({ - palette: palettes.light, - typography: { - ...defaultTypography, - htmlFontSize: 16, - fontFamily: 'My-Custom-Font', - h1: { - fontSize: 72, - fontWeight: 700, - marginBottom: 10, - fontFamily: 'My-Awesome-Font', - }, - }, - defaultPageTheme: 'home', - }), -}); -``` - -## Overriding Backstage and Material UI components styles - -When creating a custom theme you would be applying different values to component's CSS rules that use the theme object. For example, a Backstage component's styles might look like this: - -```tsx -const useStyles = makeStyles( - theme => ({ - header: { - padding: theme.spacing(3), - boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)', - backgroundImage: theme.page.backgroundImage, - }, - }), - { name: 'BackstageHeader' }, -); -``` - -Notice how the `padding` is getting its value from `theme.spacing`, that means that setting a value for spacing in your custom theme would affect this component padding property and the same goes for `backgroundImage` which uses `theme.page.backgroundImage`. However, the `boxShadow` property doesn't reference any value from the theme, that means that creating a custom theme wouldn't be enough to alter the `box-shadow` property or to add css rules that aren't already defined like a margin. For these cases you should also create an override. - -Here's how you would do that: - -```ts title="packages/app/src/theme/myTheme.ts" -import { - createBaseThemeOptions, - createUnifiedTheme, - palettes, -} from '@backstage/theme'; - -export const myTheme = createUnifiedTheme({ - ...createBaseThemeOptions({ - palette: palettes.light, - }), - fontFamily: 'Comic Sans MS', - defaultPageTheme: 'home', - components: { - BackstageHeader: { - styleOverrides: { - header: ({ theme }) => ({ - width: 'auto', - margin: '20px', - boxShadow: 'none', - borderBottom: `4px solid ${theme.palette.primary.main}`, - }), - }, - }, - }, -}); -``` - -## Custom Logo - -In addition to a custom theme, you can also customize the logo displayed at the far top left of the site. - -In your frontend app, locate `src/components/Root/` folder. You'll find two components: - -- `LogoFull.tsx` - A larger logo used when the Sidebar navigation is opened. -- `LogoIcon.tsx` - A smaller logo used when the Sidebar navigation is closed. - -To replace the images, you can simply replace the relevant code in those components with raw SVG definitions. - -You can also use another web image format such as PNG by importing it. To do this, place your new image into a new subdirectory such as `src/components/Root/logo/my-company-logo.png`, and then add this code: - -```tsx -import MyCustomLogoFull from './logo/my-company-logo.png'; - -const LogoFull = () => { - return ; -}; -``` - -## Icons - -So far you've seen how to create your own theme and add your own logo, in the following sections you'll be shown how to override the existing icons and how to add more icons - -### Custom Icons - -You can also customize the Project's _default_ icons. - -You can change the following [icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx). - -#### Requirements - -- Files in `.svg` format -- React components created for the icons - -#### Create React Component - -In your front-end application, locate the `src` folder. We suggest creating the `assets/icons` directory and `CustomIcons.tsx` file. - -```tsx title="customIcons.tsx" -import { SvgIcon, SvgIconProps } from '@material-ui/core'; - -export const ExampleIcon = (props: SvgIconProps) => ( - - - -); -``` - -#### Using the custom icon - -Supply your custom icon in `packages/app/src/App.tsx` - -```tsx title="packages/app/src/App.tsx" -/* highlight-add-next-line */ -import { ExampleIcon } from './assets/icons/CustomIcons' - - -const app = createApp({ - apis, - components: { - {/* ... */} - }, - themes: [ - {/* ... */} - ], - /* highlight-add-start */ - icons: { - github: ExampleIcon, - }, - /* highlight-add-end */ - bindRoutes({ bind }) { - {/* ... */} - } -}) -``` - -### Adding Icons - -You can add more icons, if the [default icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx) do not fit your needs, so that they can be used in other places like for Links in your entities. For this example we'll be using icons from[Material UI](https://v4.mui.com/components/material-icons/) and specifically the `AlarmIcon`. Here's how to do that: - -1. First you will want to open your `App.tsx` in `/packages/app/src` -2. Then you want to import your icon, add this to the rest of your imports: `import AlarmIcon from '@material-ui/icons/Alarm';` -3. Next you want to add the icon like this to your `createApp`: - - ```tsx title="packages/app/src/App.tsx" - const app = createApp({ - apis: ..., - plugins: ..., - /* highlight-add-start */ - icons: { - alert: AlarmIcon, - }, - /* highlight-add-end */ - themes: ..., - components: ..., - }); - ``` - -4. Now we can reference `alert` for our icon in our entity links like this: - - ```yaml - apiVersion: backstage.io/v1alpha1 - kind: Component - metadata: - name: artist-lookup - description: Artist Lookup - links: - - url: https://example.com/alert - title: Alerts - icon: alert - ``` - - And this is the result: - - ![Example Link with Alert icon](../assets/getting-started/add-icons-links-example.png) - - Another way you can use these icons is from the `AppContext` like this: - - ```ts - import { useApp } from '@backstage/core-plugin-api'; - - const app = useApp(); - const alertIcon = app.getSystemIcon('alert'); - ``` - - You might want to use this method if you have an icon you want to use in several locations. - -:::note Note - -If the icon is not available as one of the default icons or one you've added then it will fall back to Material UI's `LanguageIcon` - -::: - -## Custom Sidebar - -As you've seen there are many ways that you can customize your Backstage app. The following section will show you how you can customize the sidebar. - -### Sidebar Sub-menu - -For this example we'll show you how you can expand the sidebar with a sub-menu: - -1. Open the `Root.tsx` file located in `packages/app/src/components/Root` as this is where the sidebar code lives -2. Then we want to add the following import for `useApp`: - - ```tsx title="packages/app/src/components/Root/Root.tsx" - import { useApp } from '@backstage/core-plugin-api'; - ``` - -3. Then update the `@backstage/core-components` import like this: - - ```tsx title="packages/app/src/components/Root/Root.tsx" - import { - Sidebar, - sidebarConfig, - SidebarDivider, - SidebarGroup, - SidebarItem, - SidebarPage, - SidebarScrollWrapper, - SidebarSpace, - useSidebarOpenState, - Link, - /* highlight-add-start */ - GroupIcon, - SidebarSubmenu, - SidebarSubmenuItem, - /* highlight-add-end */ - } from '@backstage/core-components'; - ``` - -4. Finally replace `` with this: - - ```tsx title="packages/app/src/components/Root/Root.tsx" - - - - - - - - - - - - - - ``` - -When you startup your Backstage app and hover over the Home option on the sidebar you'll now see a nice sub-menu appear with links to the various Kinds in your Catalog. It would look like this: - -![Sidebar sub-menu example](./../assets/getting-started/sidebar-submenu-example.png) - -You can see more ways to use this in the [Storybook Sidebar examples](https://backstage.io/storybook/?path=/story/layout-sidebar--sample-scalable-sidebar) - -## Custom Homepage - -In addition to a custom theme, a custom logo, you can also customize the -homepage of your app. Read the full guide on the [next page](homepage.md). - -## Migrating to Material UI v5 - -We now support Material UI v5 in Backstage. Check out our [migration guide](../tutorials/migrate-to-mui5.md) to get started. diff --git a/microsite/sidebars.ts b/microsite/sidebars.ts index 5a408d5d1f..b7e89825ca 100644 --- a/microsite/sidebars.ts +++ b/microsite/sidebars.ts @@ -35,7 +35,6 @@ export default { 'getting-started/config/database', 'getting-started/config/authentication', 'getting-started/configure-app-with-plugins', - 'getting-started/app-custom-theme', 'getting-started/homepage', ], }, @@ -398,6 +397,16 @@ export default { 'conf/reading', 'conf/writing', 'conf/defining', + { + type: 'category', + label: 'User Interface', + items: [ + 'conf/user-interface/index', + 'conf/user-interface/logo', + 'conf/user-interface/icons', + 'conf/user-interface/sidebar', + ], + }, ], Framework: [ {