
Security News
/Research
Popular node-ipc npm Package Infected with Credential Stealer
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.
@lightspeed/cirrus-sidebar
Advanced tools
The composable and reusable <Sidebar> component. Since these components are very flexible, it's
recommended to build your own abstraction specific to your product on top of this.
ℹ️ Note: The implementation of the breakpoints (when to hide) and animation is up to the consumer of this package as of now.
First, make sure you have been through the install steps steps required to add Flame in your application. Although it's not required to have Flame installed to use Logo, you will need to install its peer dependencies.
If using Yarn:
yarn add @lightspeed/cirrus-sidebar
Or using npm:
npm i -S @lightspeed/cirrus-sidebar
Because the <Sidebar> is completely unknown in what environment it's being rendered and at what breakpoints
the sidebar should hide, we open up a couple of animation styles for you to use.
These styles are exposed at @lightspeed/cirrus-sidebar/styles.
These constants are exposed at @lightspeed/cirrus-sidebar/styles/constants.
import styled from '@emotion/styled';
import { slideInDurationMs, slideInBezier } from '@lightspeed/cirrus-sidebar/styles';
import { PAGE_HEADER_HEIGHT, SIDEBAR_WIDTH } from '@lightspeed/cirrus-sidebar/styles/constants';
import { Sidebar } from '@lightspeed/cirrus-sidebar';
const SidebarWrapper = styled.div`
position: absolute;
left: -${SIDEBAR_WIDTH}px;
top: 0;
bottom: 0;
transition: left ${slideInDurationMs} ${slideInBezier};
${props => props.active && 'left: 0;'}
@media (min-device-width: 480px) {
left: 0;
}
`;
const App = () => (
<SidebarWrapper>
<Sidebar>Sidebar content here</Sidebar>
</SidebarWrapper>
);
export default App;
import React from 'react';
import { Text } from '@lightspeed/cirrus-text';
import Icon from '@lightspeed/cirrus-icon';
import {
Sidebar,
SidebarHeader,
SidebarAppSwitcher,
SidebarShopButton,
SidebarDropdownButton,
SidebarAccountDropdown,
SidebarMenu,
SidebarMenuItem,
SidebarItem,
SidebarNotificationBadge,
SidebarNav,
SidebarFooter,
SidebarFooterItem,
} from '@lightspeed/cirrus-sidebar';
const items = [
{ icon: <Icon name="home" />, children: 'Home', href: '/', active: true },
{ icon: <Icon name="statistics" />, children: 'Statistics', href: 'statistics' },
{
icon: <Icon name="orders" />,
children: 'Orders',
href: 'orders',
hasSublevel: true,
notifications: <SidebarNotificationBadge>2</SidebarNotificationBadge>,
},
{ icon: <Icon name="products" />, children: 'Products', href: 'products', hasSublevel: true },
{ icon: <Icon name="customers" />, children: 'Customers', href: 'customers', hasSublevel: true },
{ icon: <Icon name="design" />, children: 'Design', href: 'themes', hasSublevel: true },
{ icon: <Icon name="content" />, children: 'Content', href: 'pages', hasSublevel: true },
{
icon: <Icon name="discount-rules" />,
children: 'Marketing',
href: 'discount_codes',
hasSublevel: true,
},
{
icon: <Icon name="blogs" />,
children: 'Blogs',
href: 'blogs',
onClick: e => {
e.preventDefault();
console.log('You can also just hook into the item through onClick!');
},
hasSublevel: true,
},
{
icon: <Icon name="apps" />,
children: 'Apps',
href: 'store/apps/dashboard',
disabled: true,
hasSublevel: true,
},
{ icon: <Icon name="tools" />, children: 'Tools', href: 'imports', hasSublevel: true },
{ icon: <Icon name="settings" />, children: 'Settings', href: 'settings', disabled: true },
];
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isUserMenuOpen: false,
};
this.openUserMenu = this.openUserMenu.bind(this);
this.closeUserMenu = this.closeUserMenu.bind(this);
}
openUserMenu() {
this.setState(() => ({
isUserMenuOpen: true,
}));
}
closeUserMenu() {
this.setState(() => ({
isUserMenuOpen: true,
}));
}
render() {
const { isUserMenuOpen } = this.state;
return (
<div>
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher
currentProduct="ecom"
canSwitchTo={[{ name: 'retail', href: '/retail' }]}
/>
<SidebarShopButton>
<Text color="snow">SEOshop</Text>
<Text color="snow">http://shop1.webshopapp.dev/</Text>
</SidebarShopButton>
<SidebarAccountDropdown
isOpen={isUserMenuOpen}
onOpen={this.openUserMenu}
onClose={this.closeUserMenu}
target={({ targetProps, targetEvents }) => (
<SidebarDropdownButton {...targetProps} {...targetEvents} active={isUserMenuOpen}>
Awesome Merchant
</SidebarDropdownButton>
)}
>
<SidebarMenu>
<SidebarMenuItem href="#">Tasks</SidebarMenuItem>
<SidebarMenuItem href="#">My Account</SidebarMenuItem>
<SidebarMenuItem href="#" danger>
Logout
</SidebarMenuItem>
</SidebarMenu>
</SidebarAccountDropdown>
</SidebarHeader>
<SidebarNav>
<ul>
{items.map(item => (
<SidebarItem key={item.title} {...item} />
))}
</ul>
</SidebarNav>
<SidebarFooter>
<SidebarFooterItem
icon={<Icon name="help" />}
href="#"
target="_blank"
rel="noopener noreferrer"
>
Help
</SidebarFooterItem>
<SidebarFooterItem icon={<Icon name="search" />} href="#">
Search
</SidebarFooterItem>
</SidebarFooter>
</Sidebar>
</div>
);
}
}
export default MyComponent;
The wrapper of the sidebar (controls the width and color).
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import { Sidebar } from '@lightspeed/cirrus-sidebar';
const App = () => <Sidebar>My content here</Sidebar>;
export default App;
The top part of the sidebar (contains the appswitcher, shopbutton and account menu). This element divides the top part of the sidebar from the main navigation and the footer.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the sidebar |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import { Sidebar, SidebarHeader } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>Your header stuff here</SidebarHeader>
<nav>Other stuff here</nav>
</Sidebar>
);
export default App;
This component is responsible for showing the correct current app and what apps the user can switch to.
| Prop | Type | Required? | Description |
|---|---|---|---|
currentProduct | `ecom | retail` | Yes |
canSwitchTo | Array<ProductT> | No | The list of products that the user can switch to |
logoProps | Object | No | The props you want to pass to the logo (such as href, onClick, etc.) |
triggerProps | Object | No | The props you want to pass to the "switch products" button |
appsConfig | AppsConfig | No | An object that allows you to add new apps to switch to (see info down below) |
The apps config is an object with the key being the app identifier and the value being the app logo. This allows you to then use these as the currentProduct and within the switchable apps array.
Note: This does not override existing apps (e.g. retail and ecom will still remain available)
const appsConfig = {
customApp: <svg />,
anotherApp: <svg />,
};
<SidebarAppSwitcher
appsConfig={appsConfig}
currentProduct="customApp"
canSwitchTo={[{ name: 'retail', href: '/retail' }, { name: 'anotherApp', href: '/another-app' }]}
/>;
import React from 'react';
import { Sidebar, SidebarHeader, SidebarAppSwitcher } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher currentProduct="ecom" />
</SidebarHeader>
</Sidebar>
);
export default App;
import React from 'react';
import { Sidebar, SidebarHeader, SidebarAppSwitcher } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher
currentProduct="ecom"
canSwitchTo={[{ name: 'retail', href: '/retail' }]}
/>
</SidebarHeader>
</Sidebar>
);
export default App;
import React from 'react';
import { Sidebar, SidebarHeader, SidebarAppSwitcher } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher
currentProduct="ecom"
canSwitchTo={[
{
name: 'retail',
onClick: e => {
e.preventDefault();
router.goTo('/retail');
},
},
]}
/>
</SidebarHeader>
</Sidebar>
);
export default App;
import React from 'react';
import { Sidebar, SidebarHeader, SidebarAppSwitcher } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher
appsConfig={{ customProduct: '🔥' }}
currentProduct="ecom"
canSwitchTo={[
{ name: 'retail', href: '/retail' },
{ name: 'customProduct', href: '/custom-product' },
]}
/>
</SidebarHeader>
</Sidebar>
);
export default App;
import React from 'react';
import { Sidebar, SidebarHeader, SidebarAppSwitcher } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher logoProps={{ href: '/' }} currentProduct="ecom" />
</SidebarHeader>
</Sidebar>
);
export default App;
import React from 'react';
import { Sidebar, SidebarHeader, SidebarAppSwitcher } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarAppSwitcher
triggerProps={{ 'data-test': 'sidebar-product-trigger' }}
currentProduct="ecom"
/>
</SidebarHeader>
</Sidebar>
);
export default App;
The button that is all around the current shop and register.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
active | boolean | Whether the shop button is currently active |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import { Text } from '@lightspeed/cirrus-text';
import { SidebarShopButton } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>
<SidebarShopButton onClick={() => router.goTo('/switch')}>
<Text color="snow">SEOshop</Text>
<Text color="snow">http://shop1.webshopapp.dev/</Text>
</SidebarShopButton>
</SidebarHeader>
</Sidebar>
);
export default App;
The dropdown button that is used for opening menus (contains an icon that indicates that a menu will open).
See <SidebarAccountDropdown> for an example.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...rest | Any | Any prop you want to add to this element |
See <SidebarAccountDropdown> for an example.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...rest | Any | Any prop you want to add to this element |
The menu item for the <SidebarMenu>.
See <SidebarAccountDropdown> for an example.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
danger | boolean | Whether the item is danger styled |
...rest | Any | Any prop you want to add to this element |
The Sidebar popover menu. Renders a cirrus-popover with some customized positional styles.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...cirrusPopoverProps | Object | Any props defined within the cirrus-popover |
import React from 'react';
import { Text } from '@lightspeed/cirrus-text';
import {
Sidebar,
SidebarHeader,
SidebarAccountDropdown,
SidebarDropdownButton,
SidebarMenu,
SidebarMenuItem,
} from '@lightspeed/cirrus-sidebar';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isUserMenuOpen: false,
};
this.openUserMenu = this.openUserMenu.bind(this);
this.closeUserMenu = this.closeUserMenu.bind(this);
}
openUserMenu() {
this.setState(() => ({
isUserMenuOpen: true,
}));
}
closeUserMenu() {
this.setState(() => ({
isUserMenuOpen: true,
}));
}
render() {
const { isUserMenuOpen } = this.state;
return (
<Sidebar>
<SidebarHeader>
<SidebarAccountDropdown
isOpen={isUserMenuOpen}
onOpen={this.openUserMenu}
onClose={this.closeUserMenu}
target={({ targetProps, targetEvents }) => (
<SidebarDropdownButton {...targetProps} {...targetEvents} active={isUserMenuOpen}>
Awesome Merchant
</SidebarDropdownButton>
)}
>
<SidebarMenu>
<SidebarMenuItem href="#">Tasks</SidebarMenuItem>
<SidebarMenuItem href="#">My Account</SidebarMenuItem>
<SidebarMenuItem href="#" danger>
Logout
</SidebarMenuItem>
</SidebarMenu>
</SidebarAccountDropdown>
</SidebarHeader>
</Sidebar>
);
}
}
export default MyComponent;
The <nav> element styled for the Sidebar.
Note: Automatically removes the
list-stylefrom a direct child<ul>tag.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import { Text } from '@lightspeed/cirrus-text';
import { Sidebar, SidebarHeader, SidebarNav } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>The header here</SidebarHeader>
<SidebarNav>
<ul>
<li>Your nav items here</li>
</ul>
</SidebarNav>
</Sidebar>
);
export default App;
The sidebar navigation link (<a>).
| Prop | Type | Description |
|---|---|---|
icon | React.Node | Can render any icon (preferably the a cirrus-icon) |
children | React.Node | The navigation item's title |
href | string | The url of the navigation item (should be present) |
active | boolean | Whether the navigation link is currently active |
disabled | boolean | Whether the navigation link is disabled (only appears disabled) |
notifications | React.Node | Allows for showing notifications for this navigation link |
hasSublevel | boolean | Whether this navigation link has a sub level navigation |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import Icon from '@lightspeed/cirrus-icon';
import { Text } from '@lightspeed/cirrus-text';
import { Sidebar, SidebarHeader, SidebarNav, SidebarItem } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>The header here</SidebarHeader>
<SidebarNav>
<ul>
<li>
<SidebarItem icon={<Icon name="home" />} href="/">
Home
</SidebarItem>
</li>
</ul>
</SidebarNav>
</Sidebar>
);
export default App;
When passing onClick, you should still pass a href as well, to indicate
that the element is interactable.
import React from 'react';
import Icon from '@lightspeed/cirrus-icon';
import { Text } from '@lightspeed/cirrus-text';
import { Sidebar, SidebarHeader, SidebarNav, SidebarItem } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>The header here</SidebarHeader>
<SidebarNav>
<ul>
<li>
<SidebarItem
icon={<Icon name="home" />}
href="/"
onClick={e => {
e.preventDefault();
router.goTo('/');
}}
>
Home
</SidebarItem>
</li>
</ul>
</SidebarNav>
</Sidebar>
);
export default App;
The notification badge that can be used within the <SidebarItem />'s notifications prop.
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import Icon from '@lightspeed/cirrus-icon';
import { Text } from '@lightspeed/cirrus-text';
import {
Sidebar,
SidebarHeader,
SidebarNav,
SidebarItem,
SidebarNotificationBadge,
} from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>The header here</SidebarHeader>
<SidebarNav>
<ul>
<li>
<SidebarItem
icon={<Icon name="home" />}
href="/"
notifications={<SidebarNotificationBadge>2</SidebarNotificationBadge>}
>
Home
</SidebarItem>
</li>
</ul>
</SidebarNav>
</Sidebar>
);
export default App;
The <footer> styled for the Sidebar
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the button |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import Icon from '@lightspeed/cirrus-icon';
import { Text } from '@lightspeed/cirrus-text';
import { Sidebar, SidebarHeader, SidebarNav, SidebarFooter } from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>The header here</SidebarHeader>
<SidebarNav>Nav here</SidebarNav>
<SidebarFooter>The Footer goes here</SidebarFooter>
</Sidebar>
);
export default App;
The items that go inside the footer (renders a <a>).
| Prop | Type | Description |
|---|---|---|
children | React.ReactNode | The content to display inside the footer item |
icon | React.ReactNode | The icon to render inside the footer item |
...rest | Any | Any prop you want to add to this element |
import React from 'react';
import Icon from '@lightspeed/cirrus-icon';
import { Text } from '@lightspeed/cirrus-text';
import {
Sidebar,
SidebarHeader,
SidebarNav,
SidebarFooter,
SidebarFooterItem,
} from '@lightspeed/cirrus-sidebar';
const App = () => (
<Sidebar>
<SidebarHeader>The header here</SidebarHeader>
<SidebarNav>Nav here</SidebarNav>
<SidebarFooter>
<SidebarFooterItem icon={<Icon name="help" />} href="/help">
Help
</SidebarFooterItem>
</SidebarFooter>
</Sidebar>
);
export default App;
FAQs
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.

Security News
TeamPCP and BreachForums are promoting a Shai-Hulud supply chain attack contest with a $1,000 prize for the biggest package compromise.

Security News
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.