VerticalBar

A vertical bar is a flexible container that organizes items vertically.

installyarn add @clayui/core
versionNPM Version
useimport {VerticalBar} from '@clayui/core';

Example

import {Button, Provider, VerticalBar} from '@clayui/core';
import Icon from '@clayui/icon';

import '@clayui/css/lib/css/atlas.css';

const spritemap = '/public/icons.svg';

export default function App() {
	const items = [
		{
			icon: 'tag',
			title: 'Tag',
		},
		{
			divider: true,
			icon: 'message',
			title: 'Message',
		},
		{
			icon: 'effects',
			title: 'Effects',
		},
	];

	return (
		<div style={{height: '400px'}}>
			<Provider spritemap={spritemap}>
				<VerticalBar absolute defaultActive="Tag">
					<VerticalBar.Content items={items}>
						{(item) => (
							<VerticalBar.Panel key={item.title}>
								<div className="sidebar-header">
									<div className="component-title">
										{item.title}
									</div>
								</div>
							</VerticalBar.Panel>
						)}
					</VerticalBar.Content>

					<VerticalBar.Bar displayType="light" items={items}>
						{(item) => (
							<VerticalBar.Item
								divider={item.divider}
								key={item.title}
							>
								<Button
									aria-label={'Open ' + item.title}
									displayType={null}
								>
									<Icon symbol={item.icon} />
								</Button>
							</VerticalBar.Item>
						)}
					</VerticalBar.Bar>
				</VerticalBar>
			</Provider>
		</div>
	);
}

Introduction

VerticalBar allows rendering a vertical navigation bar positioned fixedly on the right or left side with the Panel that can contain any element referring to the desired action. An item in the vertical bar also does not need to have an equivalent panel, it can be an action button or link to be navigated.

Just like the TreeView component, the VerticalBar is considered a middle-level component instead of a low-level or high-level, it guarantees more flexibility and composition and delivers features that would only be available at high-level with the same synthetic form of an API low-level.

Content

As VerticalBar is middle-level, it allows you to build static or dynamic content if you need to consume data from some service.

The component controls the OOTB state to toggle the visibility of the panels ie you can quickly build with zero-config, either defining static or dynamic content.

<VerticalBar>
	<VerticalBar.Content>
		<VerticalBar.Panel>Tag</VerticalBar.Panel>
		<VerticalBar.Panel>Message</VerticalBar.Panel>
	</VerticalBar.Content>
	<VerticalBar.Bar>
		<VerticalBar.Item>
			<Button displayType={null}>
				<Icon symbol="tag" />
			</Button>
		</VerticalBar.Item>
		<VerticalBar.Item divider>
			<Button displayType={null}>
				<Icon symbol="message" />
			</Button>
		</VerticalBar.Item>
		<VerticalBar.Item>
			<Button
				displayType={null}
				onClick={(event) => {
					event.preventDefault();

					// Dispatch some action
				}}
			>
				<Icon symbol="effects" />
			</Button>
		</VerticalBar.Item>
	</VerticalBar.Bar>
</VerticalBar>

The declaration order is important for the component to know which Panel should be visible when the user clicks on some button on the bar, this can also be configurable if the key property is set in both components to associate a unique id and create the relationship.

<VerticalBar>
	<VerticalBar.Content>
		<VerticalBar.Panel key="tag">Tag</VerticalBar.Panel>
	</VerticalBar.Content>
	<VerticalBar.Bar>
		<VerticalBar.Item key="tag">
			<Button displayType={null}>
				<Icon symbol="tag" />
			</Button>
		</VerticalBar.Item>
	</VerticalBar.Bar>
</VerticalBar>

Static

Declaring components and the list of panels and hard coded items that are not configured by any user or maintained in a data service is considered static content, as in this example:

<VerticalBar>
	<VerticalBar.Content>
		<VerticalBar.Panel>Tag</VerticalBar.Panel>
		<VerticalBar.Panel>Message</VerticalBar.Panel>
		<VerticalBar.Panel>Effects</VerticalBar.Panel>
	</VerticalBar.Content>
	<VerticalBar.Bar>
		<VerticalBar.Item>
			<Button displayType={null}>
				<Icon symbol="tag" />
			</Button>
		</VerticalBar.Item>
		<VerticalBar.Item divider>
			<Button displayType={null}>
				<Icon symbol="message" />
			</Button>
		</VerticalBar.Item>
		<VerticalBar.Item>
			<Button displayType={null}>
				<Icon symbol="effects" />
			</Button>
		</VerticalBar.Item>
	</VerticalBar.Bar>
</VerticalBar>

Dynamic

Dynamic content is related when the component is configured through a data source or dynamic collection that can change during the component’s lifetime.

To make a component dynamic is only possible by using the properties of items and converting the children of the components to render props of <VerticalBar.Content /> and <VerticalBar.Bar /> respectively being the panels and the vertical bar items.

const items = [
	{
		icon: 'tag',
		title: 'Tag',
	},
	{
		divider: true,
		icon: 'message',
		title: 'Message',
	},
	{
		icon: 'effects',
		title: 'Effects',
	},
];

return (
	<VerticalBar defaultActive="Tag">
		<VerticalBar.Content items={items}>
			{(item) => (
				<VerticalBar.Panel key={item.title}>
					{item.title}
				</VerticalBar.Panel>
			)}
		</VerticalBar.Content>

		<VerticalBar.Bar items={items}>
			{(item) => (
				<VerticalBar.Item divider={item.divider} key={item.title}>
					<Button displayType={null}>
						<Icon symbol={item.icon} />
					</Button>
				</VerticalBar.Item>
			)}
		</VerticalBar.Bar>
	</VerticalBar>
);

Position

Positioning the VerticalBar on the right or left side is possible by setting the position property and changing the declaration order of the <VerticalBar.Panel /> and <VerticalBar.Bar /> components.

<VerticalBar position="left">
	<VerticalBar.Bar></VerticalBar.Bar>
	<VerticalBar.Content></VerticalBar.Content>
</VerticalBar>

Resize

The property resize in <VerticalBar.Bar /> enables the user to increase or decrease the panel width using the mouse or keyboard. The maximum width can be set using the property panelWidthMax. It defaults to 500px. The minimum width is set using the property panelWidthMin and defaults to 280px. The starting width is set using panelWidth with a default value of 320px.

The property onPanelWidthChange accepts a callback function that executes when the panelWidth is updated. The callback function has the value of the panel width as the parameter. It can be used to make updates to other parts of your application, such as pushing body content over as the user resizes the Vertical Bar Panel.

When using the property onPanelWidthChange, you must also declare panelWidth. Setting a fixed value for panelWidth will result in onPanelWidthChange always returning that value, you must use React.useState to get your callback function to return the correct value. Please see the code example below.

Load lazy panel

The possibility of lazy loading the panel content is a strategy to reduce the application’s bundle and load it only when it is used. Implementing in the Vertical Bar is also simple using the React.js support components, with <Suspense /> and React.lazy.

const TagPanel = React.lazy(() => import('./TagPanel'));
const MessagePanel = React.lazy(() => import('./MessagePanel'));

export const LoadLazyPanel = () => {
	const items = [
		{
			icon: 'tag',
			panel: TagPanel,
			title: 'Tag',
		},
		{
			divider: true,
			icon: 'message',
			panel: MessagePanel,
			title: 'Message',
		},
	];

	return (
		<VerticalBar>
			<VerticalBar.Content displayType="light" items={items}>
				{({panel: PanelLazy, title}) => (
					<VerticalBar.Panel key={title}>
						<Suspense fallback={<div>Loading...</div>}>
							<PanelLazy />
						</Suspense>
					</VerticalBar.Panel>
				)}
			</VerticalBar.Content>

			<VerticalBar.Bar displayType="light" items={items}>
				{(item) => (
					<VerticalBar.Item divider={item.divider} key={item.title}>
						<Button displayType={null}>
							<Icon symbol={item.icon} />
						</Button>
					</VerticalBar.Item>
				)}
			</VerticalBar.Bar>
		</VerticalBar>
	);
};

You can also use the <ErrorBoundary /> above the <Suspense /> to capture error and render some screen as a fallback, for example, if it was a network error, render a fallback with a retry reload button to fetch component again.

<VerticalBar.Content displayType="light" items={items}>
	{({panel: PanelLazy, title}) => (
		<VerticalBar.Panel key={title}>
			<ErrorBoundary>
				<Suspense fallback={<div>Loading...</div>}>
					<PanelLazy />
				</Suspense>
			</ErrorBoundary>
		</VerticalBar.Panel>
	)}
</VerticalBar.Content>