Rail
Ultra-narrow icon-only vertical navigation like VS Code's activity bar. Icons use text-muted at rest, accent-primary glow on active. Expands on hover.
<arc-rail>Overview
Rail is an ultra-narrow vertical navigation strip, typically 48 to 56 pixels wide, that displays icon-only items in a single column. It is modeled on the activity bar in VS Code and similar IDEs, and switches top-level sections without the horizontal space a full Sidebar needs. Icons render in text-muted at rest and light up with an accent-primary glow when active.
On hover, the Rail can optionally expand to reveal text labels beside each icon, sitting between icon-only navigation and a full labeled sidebar. The expanded prop controls this and can also be toggled programmatically, since some users prefer the labels visible at all times.
Rail sits at the far-left edge of an AppShell as a fixed vertical strip from top to bottom. It works alongside a contextual Sidebar: the Rail handles top-level section switching (e.g. Explorer, Search, Source Control) while the Sidebar shows the detail panel for the active section. The component dispatches arc-change on item selection so your application can swap the adjacent content area accordingly.
Guidelines
When to use
- Limit items to four to seven for a scannable icon column
- Use universally recognizable icons: Rail has no visible labels by default
- Place Rail at the far-left edge of the viewport inside an AppShell
- Pair with a Sidebar to show detail content for the active Rail section
- Provide aria-label on the Rail for screen-reader context
When not to use
- Do not use Rail as the only navigation on a content-heavy site: it is too compact
- Do not add more than seven items: vertical overflow will be confusing
- Do not rely solely on icon recognition; ensure tooltips or expand-on-hover labels are available
- Do not use Rail on mobile viewports; switch to BottomNav instead
- Do not nest a Rail inside a Sidebar: Rail replaces the sidebar for top-level switching
Features
- Ultra-narrow icon-only vertical navigation strip
- Accent-primary glow on active item, text-muted at rest
- Optional expand-on-hover to reveal text labels
- Controlled expanded prop for programmatic label visibility
- `arc-change` event on item selection
- Designed for far-left positioning in AppShell layouts
- Keyboard navigable with arrow keys and Enter activation
- Pairs with Sidebar for section-detail navigation patterns
- Token-driven theming via CSS custom properties
Preview
Usage
This component requires JavaScript. No pure HTML/CSS version is available. Use the Web Component directly or a framework wrapper.
<script type="module" src="@arclux/arc-ui"></script>
<arc-rail
value="explorer"
id="rail"
items='[
{ "icon": "folder", "label": "Explorer", "value": "explorer" },
{ "icon": "magnifying-glass", "label": "Search", "value": "search" },
{ "icon": "git-branch", "label": "Source Control", "value": "scm" },
{ "icon": "puzzle-piece", "label": "Extensions", "value": "extensions" },
{ "icon": "gear", "label": "Settings", "value": "settings" }
]'
></arc-rail>
<script>
document.querySelector('#rail').addEventListener('arc-change', (e) => {
console.log('section:', e.detail.value);
});
</script>import { Rail } from '@arclux/arc-ui-react';
const items = [
{ icon: 'folder', label: 'Explorer', value: 'explorer' },
{ icon: 'search', label: 'Search', value: 'search' },
{ icon: 'git-branch', label: 'Source Control', value: 'scm' },
{ icon: 'puzzle', label: 'Extensions', value: 'extensions' },
{ icon: 'settings', label: 'Settings', value: 'settings' },
];
export function ActivityBar() {
return (
<Rail
items={items}
value="explorer"
onArcChange={(e) => console.log('section:', e.detail.value)}
/>
);
}<script setup>
import { Rail } from '@arclux/arc-ui-vue';
const items = [
{ icon: 'folder', label: 'Explorer', value: 'explorer' },
{ icon: 'search', label: 'Search', value: 'search' },
{ icon: 'git-branch', label: 'Source Control', value: 'scm' },
{ icon: 'puzzle', label: 'Extensions', value: 'extensions' },
{ icon: 'settings', label: 'Settings', value: 'settings' },
];
function onChange(e) {
console.log('section:', e.detail.value);
}
</script>
<template>
<Rail :items="items" value="explorer" @arc-change="onChange" />
</template><script>
import { Rail } from '@arclux/arc-ui-svelte';
const items = [
{ icon: 'folder', label: 'Explorer', value: 'explorer' },
{ icon: 'search', label: 'Search', value: 'search' },
{ icon: 'git-branch', label: 'Source Control', value: 'scm' },
{ icon: 'puzzle', label: 'Extensions', value: 'extensions' },
{ icon: 'settings', label: 'Settings', value: 'settings' },
];
</script>
<Rail
{items}
value="explorer"
on:arc-change={(e) => console.log('section:', e.detail.value)}
/>import { Component } from '@angular/core';
import { Rail } from '@arclux/arc-ui-angular';
@Component({
imports: [Rail],
template: `
<arc-rail
[items]="items"
value="explorer"
(arc-change)="onChange($event)"
/>
`,
})
export class ActivityBarComponent {
items = [
{ icon: 'folder', label: 'Explorer', value: 'explorer' },
{ icon: 'search', label: 'Search', value: 'search' },
{ icon: 'git-branch', label: 'Source Control', value: 'scm' },
{ icon: 'puzzle', label: 'Extensions', value: 'extensions' },
{ icon: 'settings', label: 'Settings', value: 'settings' },
];
onChange(e: CustomEvent) {
console.log('section:', e.detail.value);
}
}import { Rail } from '@arclux/arc-ui-solid';
const items = [
{ icon: 'folder', label: 'Explorer', value: 'explorer' },
{ icon: 'search', label: 'Search', value: 'search' },
{ icon: 'git-branch', label: 'Source Control', value: 'scm' },
{ icon: 'puzzle', label: 'Extensions', value: 'extensions' },
{ icon: 'settings', label: 'Settings', value: 'settings' },
];
export function ActivityBar() {
return (
<Rail
items={items}
value="explorer"
onArcChange={(e) => console.log('section:', e.detail.value)}
/>
);
}import { Rail } from '@arclux/arc-ui-preact';
const items = [
{ icon: 'folder', label: 'Explorer', value: 'explorer' },
{ icon: 'search', label: 'Search', value: 'search' },
{ icon: 'git-branch', label: 'Source Control', value: 'scm' },
{ icon: 'puzzle', label: 'Extensions', value: 'extensions' },
{ icon: 'settings', label: 'Settings', value: 'settings' },
];
export function ActivityBar() {
return (
<Rail
items={items}
value="explorer"
onArcChange={(e) => console.log('section:', e.detail.value)}
/>
);
}API
itemsArray<{icon: string, label: string, value: string}>[]- Array of navigation items, each with an icon name, text label, and value identifier.
valuestring''- The value of the currently active item. Controls which icon receives the accent glow.
expandedbooleanfalse- When true, the Rail widens to show text labels beside each icon. Can be toggled on hover or set permanently.
Events
arc-changedetail:{ value: string }- Fired when an item is selected with detail: { value }.
See Also
- SidebarCollapsible navigation sidebar with grouped sections, heading labels, and active link highlighting. Suited to documentation sites, admin panels, and any layout that needs persistent vertical navigation.
- Navigation MenuHorizontal navigation bar with hover-triggered dropdown sub-menus and full keyboard accessibility. Designed for marketing sites, documentation hubs, and product landing pages where top-level sections expand into categorised link lists.
- Bottom NavMobile bottom bar with icon and label items. The active item gets an accent-primary glow underline on a surface-overlay background with backdrop blur.