Create a custom Sidebar component
Superblocks supports adding Custom Components to the frontend of your Applications. In this guide, you will learn how to use a custom React component alongside the out-of-the-box Tabs component in Superblocks to build a multi-page app experience.
Note that the individual pages will not have their own route (i.e. the URL will be static as the user navigates through the app). Multi-page apps with dedicated URL routes per page are currently in beta. Feel free to reach out to our support in case you have any questions.
Step-by-step guide
You can either follow the step-by-step guide to create the custom Sidebar component from scratch or jump to this section, which provides you with a pre-built version of the Sidebar that you can import into your Superblocks Application.
As you follow the steps below to create the Sidebar component, you can consult the final version of the code in this GitHub repository to compare it with your own work.
Material UI List component
In this guide, we are going to use a customized list component from the Material UI component library.
Install the Superblocks CLI
If you haven't yet installed the Superblocks CLI, go through Step 1 of the custom component Quickstart to install it.
Create your Sidebar component locally
Next, you need to configure your component. Let's use the Superblocks CLI to create the component locally.
First, we'll navigate into the application directory that we initialized above.
cd apps/[MY_APPLICATION_DIRECTORY]
Then, we'll run the create
command to initialize our component locally.
superblocks components create
Follow the wizard in the Superblocks CLI and make the following selections:
- Would you like to generate an example custom component? N
- What is the display name of the component you want to create? (e.g. To-Do List) Sidebar
- What is the machine readable name of the component you want to create? Sidebar
- Does this component have properties? Y
- What is the path of the property? This will be used to access the property in your code (e.g. currentTasks) items
- What is the type of items? any (raw expression)
- Should this property be shown in the properties panel? Y
- What is the label of the property? (e.g. Tasks) Navigation items
- Do you want to add another property? Y
- What is the path of the property? This will be used to access the property in your code (e.g. currentTasks) selectedItem
- What is the type of items? string
- Should this property be shown in the properties panel? N
- Do you want to add another property? N
- Does this component have events? Y
- What is the label of the event? (e.g. On Change) onItemSelect
- What is the path of the event? This will be used to trigger the event in your code (e.g. onChange) onItemSelect
- Do you want to add another event? N
The CLI will now create your custom component project files. Open your application folder in your favorite IDE (e.g. VS Code) to inspect them:
In the /components
directory Superblocks has created a Sidebar folder that contains the following files: component.tsx
, config.ts
, types.ts
.
Please have a look at the custom component Quickstart to learn more about the files that have been generated for your Sidebar component.
Add the Material UI code to your custom component directory
Now, navigate to the Material UI list component, select TS (TypeScript) and click on the Show Code button located below the component preview to reveal the React code for the List component:
In VS Code, open the component.tsx
, then copy and paste all import statements from the component code on the Material UI website right below the existing import statements of your Superblocks component in your editor.
In the screenshot, you can see that VS Code is unable to locate the packages for the import statements you've added to your component.tsx
, as indicated by the red underlines. Open a Terminal in VS Code and execute the following command to install the necessary JavaScript libraries:
npm install @mui/icons-material @mui/material @emotion/styled @emotion/react
Your editor should now be able to detect the libraries and the error messages should go away.
Next let's copy over the rest of the Component's code from the Matrial UI website. First, start by copying and pasting the data array right below the import statements in your component.tsx
:
const data = [
{ icon: <People />, label: 'Authentication' },
{ icon: <Dns />, label: 'Database' },
{ icon: <PermMedia />, label: 'Storage' },
{ icon: <Public />, label: 'Hosting' },
];
Next, copy the definition of FireNav and paste it below the data array in your component.tsx
:
const FireNav = styled(List)<{ component?: React.ElementType }>({
'& .MuiListItemButton-root': {
paddingLeft: 24,
paddingRight: 24,
},
'& .MuiListItemIcon-root': {
minWidth: 0,
marginRight: 16,
},
'& .MuiSvgIcon-root': {
fontSize: 20,
},
});
Now you can go on and replace your component's return statement with the return statement from the Material UI component that has the Sidebar's JSX. Replace the following code:
With this code from the Material UI component:
Next, you can navigate to your Superblocks Application and preview your custom Sidebar component in Local Dev Mode. First, open your Terminal and run the following command:
superblocks components watch
Once the watch command is running successfully:
You can navigate to your Superblocks Application and turn on the Local Dev Mode:
The custom Sidebar component should now appear under Custom Components in the Components panel:
Drag and drop your component to the Canvas:
You've successfully added the Material UI List component to your Superblocks Application. You can use the Superblocks CLI to upload your Custom Component to your Superblocks Application for the first time. Open your Terminal and run the following command:
superblocks components upload
In the next sections we will make the Sidebar component functional.
Allow users to pass custom navigation items
Paste the following JSON into the Navigation items input field in the properties panel:
[{
key: 'first-section',
label: 'First section',
type: 'group',
children: [{
key: 'authentication',
label: 'Authentication',
icon: 'People'
},{
key: 'database',
label: 'Database',
icon: 'Dns',
disabled: true
}]
}, {
key: 'second-section',
label: 'Second section',
type: 'group',
children: [{
key: 'storage',
label: 'Storage',
icon: 'PermMedia'
},{
key: 'hosting',
label: 'Hosting',
icon: 'Public'
}]
}]
Replace this code in the component.tsx
file that we added earlier when we migrated the Material UI component:
const data = [
{ icon: <People />, label: 'Authentication' },
{ icon: <Dns />, label: 'Database' },
{ icon: <PermMedia />, label: 'Storage' },
{ icon: <Public />, label: 'Hosting' },
];
with the following code:
const ICON_MAP: { [key: string]: any } = {
People: <People />,
Dns: <Dns />,
PermMedia: <PermMedia />,
Public: <Public />,
// ... add other icons to the map
};
Then, replace the entire return() statement in the component.tsx
file with this code:
return (
<Box sx={{ display: 'flex' }}>
<ThemeProvider
theme={createTheme({
components: {
MuiListItemButton: {
defaultProps: {
disableTouchRipple: true,
},
},
},
palette: {
primary: { main: 'rgb(102, 157, 246)' },
background: { paper: 'rgb(5, 30, 52)' },
},
})}
>
<Paper elevation={0} sx={{ maxWidth: 256 }}>
<FireNav component="nav" disablePadding>
<div>
{items.map((item: any) => {
return (
<div key={item.key} style={{ paddingBottom: "8px" }}>
<ListItemText
primary={item.label}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 400,
lineHeight: "16px",
color: 'white',
padding: "8px 0px",
marginBottom: "2px",
}}
/>
{item.children.map((child: any) => {
const isSelected = child.label === selectedItem;
return (
<ListItemButton
key={child.key}
sx={{
py: 0,
minHeight: 32,
borderRadius: "4px",
backgroundColor: 'white',
color: 'white',
marginBottom: "2px",
"&:hover": {
backgroundColor: 'white',
color: 'white',
},
}}
>
<ListItemIcon sx={{ color: "inherit" }}>
{ICON_MAP[child.icon]}
</ListItemIcon>
<ListItemText
primary={child.label}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 500,
color: "inherit",
}}
/>
</ListItemButton>
);
})}
</div>
);
})}
</div>
</FireNav>
</Paper>
</ThemeProvider>
</Box>
);
At this point you must provide a JSON to Navigation items in the properties panel otherwise you will see this error message: Error: Cannot read properties of undefined (reading 'map')
.
The Sidebar component should now dynamically load the JSON and render the new navigation structure:
Style the custom component
To make the Sidebar component look better, replace your component's return()
function in the component.tsx
file with the following code:
return (
<Box sx={{
display: 'flex',
border: '1px solid #E8EAED',
borderRadius: '4px',
height: '100%'
}}>
<ThemeProvider
theme={createTheme({
components: {
MuiListItemButton: {
defaultProps: {
disableTouchRipple: true,
},
},
},
palette: {
mode: 'dark',
primary: { main: 'rgb(102, 157, 246)' },
background: { paper: 'rgb(5, 30, 52)' },
},
})}
>
<Paper
elevation={0}
sx={{
maxWidth: 256,
background: "none !important",
backgroundColor: "none !important",
}}
>
<FireNav component="nav" disablePadding>
<div>
{items.map((item: any) => {
return (
<div key={item.key} style={{ paddingBottom: "8px" }}>
<ListItemText
primary={item.label}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 400,
lineHeight: "16px",
color: 'rgb(69, 77, 95)',
padding: "8px 16px",
marginBottom: "2px",
fontFamily: "Inter"
}}
/>
{item.children.map((child: any) => {
const isSelected = child.label === selectedItem;
return (
<ListItemButton
key={child.key}
sx={{
py: 0,
minHeight: 32,
borderRadius: "4px",
backgroundColor: "",
color: "#404040",
marginBottom: "2px",
fontFamily: "Inter",
"&:hover": {
backgroundColor: "black",
color: "white",
},
}}
>
<ListItemIcon sx={{ color: "inherit" }}>
{ICON_MAP[child.icon]}
</ListItemIcon>
<ListItemText
primary={child.label}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 500,
color: "inherit",
}}
/>
</ListItemButton>
);
})}
</div>
);
})}
</div>
</FireNav>
</Paper>
</ThemeProvider>
</Box>
);
When you have Local Dev Mode turned on in Superblocks, your Application should hot-reload the Sidebar component and it should now have a light design:
Optional - Add support for Dark Mode
To apply lighter font and hover colors when Dark mode is activated using Superblocks Themes, add the following to your custom Sidebar component.
In your code editor, open the config.ts
file and add the following new theme property to the list of properties:
{
path: "theme",
dataType: "any",
propertiesPanelDisplay: {"label":"Theme","controlType":"js-expr"},
isExternallyReadable: false,
isExternallySettable: true
}
You should now find the new Theme property in your component's properties panel. Then, set the property to theme
to pass the theme object to your component:
To utilize the theme
object in your custom component, you need to include theme
in the React Props passed to the component. Add the following line to your component.tsx
:
Among other properties, the theme
object contains a mode
property that can be either "DARK"
or "LIGHT"
, reflecting the user's selected mode in the Superblocks Application. When the mode is changed in Superblocks, an updated theme
object is passed to your custom Sidebar component, triggering a re-render and ensuring it updates accordingly.
Here is an extract from the theme object that will be passed to your custom component:
{
"ENTITY_TYPE": "THEME",
"colors": {
"appBackground": "#F9FAFB",
"contrastText": "#FFFFFF",
"danger": "#F45252",
"dangerLight": "#fdc5c5",
"editor": {
"builtin": "#e5ab64",
...
},
"info": "#29BBFF",
"neutral": "#FFFFFF",
"neutral100": "#E8EAED",
"neutral200": "#C6CAD2",
"neutral25": "#F9FAFB",
"neutral300": "#A4AAB7",
"neutral400": "#818A9C",
"neutral50": "#F3F4F6",
"neutral500": "#6C7689",
"neutral700": "#454D5F",
"neutral900": "#1F2633",
"primary500": "#29BBFF",
"primary600": "#00a7f5",
"primary700": "#0096db",
"primaryHighlight": "#eefaff",
"success": "#0CC26D",
"warning": "#FF9F35"
},
"fontFamily": "Roboto",
"mode": "LIGHT"
}
The colors specified in the object, such as natural100
, are primarily controlled by Superblocks and invert when the user changes the Theme from DARK
to LIGHT
or vice versa.
This allows us to replace the hardcoded colors in your custom React code with the placeholder values from the theme
object to add support for Dark Mode to your Sidebar component.
Replace your component's return()
function in the component.tsx
file with the following code:
return (
<Box sx={{
display: 'flex',
border: '1px solid #E8EAED',
borderRadius: '4px',
height: '100%'
}}>
<ThemeProvider
theme={createTheme({
components: {
MuiListItemButton: {
defaultProps: {
disableTouchRipple: true,
},
},
},
palette: {
mode: theme?.mode === "DARK" ? "dark" : "light",
primary: { main: 'rgb(102, 157, 246)' },
background: { paper: 'rgb(5, 30, 52)' },
},
})}
>
<Paper
elevation={0}
sx={{
maxWidth: 256,
background: "none !important",
backgroundColor: "none !important",
}}
>
<FireNav component="nav" disablePadding>
<div>
{items.map((item: any) => {
return (
<div key={item.key} style={{ paddingBottom: "8px" }}>
<ListItemText
primary={item.label}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 400,
lineHeight: "16px",
color: theme?.colors?.neutral700,
padding: "8px 16px",
marginBottom: "2px",
fontFamily: "Inter"
}}
/>
{item.children.map((child: any) => {
const isSelected = child.label === selectedItem;
return (
<ListItemButton
key={child.key}
sx={{
py: 0,
minHeight: 32,
borderRadius: "4px",
backgroundColor: "",
color: theme?.colors?.neutral700,
marginBottom: "2px",
fontFamily: "Inter",
"&:hover": {
backgroundColor: isSelected
? theme?.colors?.neutral900
: theme?.colors?.neutral100,
color: isSelected
? theme?.colors?.neutral
: theme?.colors?.neutral900,
},
}}
onClick={() => selectItem(child.label)}
>
<ListItemIcon sx={{ color: "inherit" }}>
{ICON_MAP[child.icon]}
</ListItemIcon>
<ListItemText
primary={child.label}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 500,
color: "inherit",
}}
/>
</ListItemButton>
);
})}
</div>
);
})}
</div>
</FireNav>
</Paper>
</ThemeProvider>
</Box>
);
Next, open your Superblocks Application in the browser and set the Mode to "Dark" using the Theme panel in the left-hand side menu. Your custom component should now adopt the inverted colors and look great in Dark Mode.
Finally, upload your component by running the superblocks components upload
in your Terminal.
Add an event handler to the custom component
When you previously used the Superblocks CLI to generate the files for the the Sidebar component you added a property called selectedItem to your component. In this section you will add logic to your component code that will update the selectedItem property to hold the name of the navigation item the user clicked on when using the Sidebar component.
You can later use this value to update the state of a Tabs component and switch to a Tab with the same name as the navigation item the user has clicked on. This is how your users will be able to navigate to a different "page".
Start by adding an onClick event handler to the <ListItem>
component in your React code in the component.tsx
file:
onClick={() => selectItem(child.label)}
Finally, add the function definition to your component.tsx
right above the return statement:
// Event handler: onItemSelect()
const selectItem = (item: any) => {
// use the provided updateProperties() method to set the *item* property
updateProperties({ selectedItem: item });
// trigger the onItemSelect event
onItemSelect();
};
Note: You can consult the final version of the code in this GitHub repository to compare it with your own work.
Congratulations, you have built a fully functional Sidebar component from scratch! In the next step, you can connect the Sidebar to a Tabs component to allow your users to navigate to a different page.
Import the pre-built component
Instead of creating the Sidebar component from scratch step-by-step using the above guide, you can also upload the final component code to your Superblocks Application by following the steps outlined below.
This Technical Guide explains how to add a custom Sidebar component to your Superblocks Applications. To learn more about Custom Components please visit this page.
Custom components need to be uploaded specifically to each Superblocks Application where you want to use them. In Step 1 below, select the URL of the Superblocks Application to which you want to upload the Sidebar component.
Steps to take:
-
[Optional] If you haven't done it yet, follow Step 1 in this guide to install the Superblocks CLI and initialize your Superblocks repository locally
-
[Optional] If you don't yet have a Components folder in
apps/[MY_APPLICATION_DIRECTORY]
, follow Step 2 in this guide to create the example To-Do List componentinfoYou don't actually need the example To-Do list component; running the above command simply helps scaffold out our local environment.
-
Clone the custom Sidebar component Github repository
-
Copy and paste the
/Sidebar
folder from the Github repository into the/components
folder of the Superblocks repository you have created in Step 1. (Place the directory on the same level as the/ToDoList
directory) -
Open
package.json
file in your editor and add the following dependencies to"dependencies"
:"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.6",
"@mui/material": "^5.15.6", -
Open a Terminal and navigate into
apps/[MY_APPLICATION_DIRECTORY]
-
In your Terminal run
npm install
to install any missing libraries for the Sidebar component -
In your Terminal run
superblocks components upload
to upload the component to your Superblocks Application -
The custom Sidebar component should now appear under Custom Components in the Components panel:
Drag and drop your component to the Canvas (Note that the Component appears empty at this point because it does not yet have navigation; we will add these in the next step):
-
Click on the Sidebar component to open the Properties Panel on the right side of the screen
-
Set Navigation items to the following code:
[{
key: 'first-section',
label: 'First section',
type: 'group',
children: [{
key: 'authentication',
label: 'Authentication',
icon: 'People'
},{
key: 'database',
label: 'Database',
icon: 'Dns',
disabled: true
}]
}, {
key: 'second-section',
label: 'Second section',
type: 'group',
children: [{
key: 'storage',
label: 'Storage',
icon: 'PermMedia'
},{
key: 'hosting',
label: 'Hosting',
icon: 'Public'
}]
}]
Connect the Sidebar to a Tabs component
Whether you followed the Step-by-step guide or Imported the pre-built component, the next steps involve adding a Tabs component to your Superblocks application to act as the container for your "pages".
The currently visible tab in a Tabs component is a settable property, meaning it can be externally set by other components, such as the Sidebar component you just added to your Application.
-
Drag and drop a Tabs component to the Canvas and place it to the right of the Sidebar component
-
Rename the Tabs to:
Authentication
Database
Storage
Hosting
-
Set the Default tab to
Authentication
-
Click on the Sidebar component to open the Properties Panel
-
Add an Action to the onItemSelect event handler
- Set the Action Type to
Set Component Property
- Set Component to
Tabs1
(assuming that this is the name of your Tabs component) - Set Value to
{{Sidebar1.selectedItem}}
(assuming that Sidebar1 is the name of your Sidebar component)
- Set the Action Type to
The custom Sidebar component should now allow you to navigate through the different tabs. Each tab acts as its own "page" within the app.
You can make a few final changes to improve the multi-page experience further:
-
Resize the Tabs component to cover the entire page.
-
Turn off the visibility of the Tabs header:
Frequently Asked Questions
How to add additional navigation items to the Sidebar component
To edit the navigation items displayed by the Sidebar component, you can modify the JSON passed to the Sidebar's Navigation Items property. Remember to update the names of the tabs in the Tabs component to exactly match the label
of each item in the JSON.
How can I change the design of the Sidebar component
You can edit the CSS in your component.tsx
file to change the design of the Sidebar component. Serve your component from your local dev server using the superblocks components watch
so that you can see live updates of the changes you make.
You can also take a look at the guide on Styling Custom Components for more general information on how to design custom components in Superblocks.