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>

API Reference

VerticalBar

typeof VerticalBar
Parameters
Properties

absolute

boolean | undefined

Flag to position the component using absolute rather than a fixed position.

activation

"manual" | "automatic" | undefined= "manual"

Flag to indicate the navigation behavior in the tab.

  • manual - it will just move the focus and tab activation is done just by pressing space or enter.
  • automatic - moves the focus to the tab and activates the tab.

children *

React.ReactNode

The VerticalBar content.

className

string | undefined

Sets the CSS className for the component.

defaultPanelWidth

number | undefined= 320

Panel width initial value (uncontrolled).

position

"left" | "right" | undefined= "right"

Sets the position of the vertical bar.

active

React.Key | null | undefined

Sets the current active panel (controlled).

defaultActive

React.Key | null | undefined

Sets the default active panel (uncontrolled).

onActiveChange

any

Callback is called when the active state changes (controlled).

onPanelWidthChange

any

Callback called when panel width changes (controlled).

panelWidth

number | undefined

Sets a custom width on the sidebar panel (controlled).

panelWidthMax

number | undefined= 500

Sets a maximum width on the sidebar panel.

panelWidthMin

number | undefined= 280

Sets a minimum width on the sidebar panel.

resize

boolean | undefined

Flag to enable resizing the sidebar panel.

Returns
Element

Bar

<T>({ children, displayType, items, virtualize, }: IProps<T>) => JSX.Element
Parameters
Properties

displayType

"light" | "dark" | undefined= "dark"

Flag to determine which style the Bar will display.

children *

React.ReactNode | ((item: T, index?: number) => React.ReactElement)

Children content to render a dynamic or static content.

items

Array<T> | undefined

Property to render content with dynamic data.

virtualize

boolean | undefined

Flag to indicate whether the list should be virtualized.

Returns
Element

Item

React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLLIElement>>
Parameters
Properties

children *

React.ReactElement<any, string | React.JSXElementConstructor<any>>

Item content.

divider

boolean | undefined

Sets the divider between items.

expand

boolean | undefined

Flag to expand the item, the next one will be aligned at the bottom of the bar.

Returns
ReactElement<any, string | JSXElementConstructor<any>> | null

Panel

({ children, keyValue, tabIndex }: Props) => JSX.Element
Parameters
Properties

children *

React.ReactNode

The panel content.

tabIndex

number | undefined

Indicates whether the panel can be focused.

Returns
Element

Content

<T>({ children, displayType, items, }: IProps<T>) => JSX.Element
Parameters
Properties

displayType

"light" | "dark" | undefined= "light"

Flag to determine which style the VerticalBar will display.

children *

React.ReactNode | ((item: T, index?: number) => React.ReactElement)

Children content to render a dynamic or static content.

items

Array<T> | undefined

Property to render content with dynamic data.

Returns
Element