A contemptably stubborn if not dictatorially restrictive navigation rail/menu–I call it a renu. Or maybe a mail. No, a navigrenuail–for Jetpack Compose with a streamlined, DSL-style API.
This “navigrenuail” provides a vertical navigation rail that expands to a full menu drawer. It is designed to be “batteries-included,” providing common behaviors and features out-of-the-box to ensure a consistent look and feel across applications.
Add JitPack to your settings.gradle.kts:
CIRCLE, SQUARE, RECTANGLE, or NONE. RECTANGLE/NONE auto-size width (fixed 36dp height).AzButton, AzToggle, AzCycler, AzDivider, AzRoller.AzRailRelocItem allows user drag-and-drop reordering within clusters.
AzTextBox: Modern text box with autocomplete and submit button.AzForm: Group multiple text boxes into a single form with a shared submit button.AzRoller: A dropdown menu that works like a roller or slot machine, cycling through options infinitely.androidx.navigation.compose.NavHost for seamless integration.AzNavHost automatically configures directional transitions (slide in/out) based on the docking side (e.g., standard LTR or mirrored for Right dock).azNestedRail allows for secondary popup rails (Vertical or Horizontal) triggered from a rail item.To use this library, add JitPack to your settings.gradle.kts:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add the dependency to your app’s build.gradle.kts:
dependencies {
implementation("com.github.HereLiesAz:AzNavRail:VERSION") // Replace VERSION with the latest release
}
This is the standard, validated way to initialize AzNavRail. It must be wrapped in AzHostActivityLayout.
import com.hereliesaz.aznavrail.*
@Composable
fun SampleScreen() {
val navController = rememberNavController()
AzHostActivityLayout(
navController = navController,
initiallyExpanded = false
) {
// 1. CONFIGURATION
azConfig(
dockingSide = AzDockingSide.LEFT,
packButtons = true, // Tightly pack rail items
displayAppName = true
)
azTheme(activeColor = Color.Cyan)
// 2. NAVIGATION ITEMS
azRailItem(id = "home", text = "Home", route = "home", content = Icons.Default.Home)
azRailItem(id = "profile", text = "Profile", route = "profile")
// 3. MENU ONLY ITEMS
azMenuItem(id = "settings", text = "Settings", route = "settings")
// 4. ONSCREEN CONTENT
// Use 'onscreen' to define your UI.
// Layout rules (safe zones, padding) are enforced automatically.
onscreen(alignment = Alignment.Center) {
AzNavHost(startDestination = "home") {
composable("home") { Text("Home Screen") }
composable("profile") { Text("Profile Screen") }
composable("settings") { Text("Settings Screen") }
}
}
}
}
AzHostActivityLayout accepts several parameters to customize its behavior:
navController: The NavHostController to use. Required.currentDestination: Explicitly set the current route. If null, it is automatically derived from the navController.isLandscape: Explicitly set the orientation. If null, it is automatically derived from the screen configuration.initiallyExpanded: Set to true to have the rail expanded by default (e.g., for bubble activities).disableSwipeToOpen: Set to true to disable the swipe gesture that opens the menu.AzHostActivityLayout enforces a “Strict Mode” layout system:
onscreen block will overlap the rail. Padding is automatically applied based on the docking side.onscreen (e.g., TopStart) are automatically mirrored if the rail is docked to the right.background(weight) DSL to place full-screen content behind the UI (e.g., maps, camera feeds). Backgrounds ignore safe zones.AzNavRail includes an interactive “Help Mode” (formerly Info Screen), ideal for onboarding or help sections.
helpEnabled = true in azAdvanced.azHelpRailItem(id, text) to place a dedicated help button in the rail.RailItem IDs to help texts to display in the help cards along with the item’s info property. The text from helpList is displayed second.helpList or info is provided.AzTextBox and AzFormAzTextBox is a text input field. AzForm is a container that groups multiple AzTextBox fields, managing them as a single entity with one submit button.
AzTextBox can be configured as a multiline input, which will automatically expand vertically as the user types. The clear and submit buttons remain anchored to the bottom right.secret mode, which masks the input. In this mode, the clear button is replaced by a reveal icon to temporarily show the password.multiline and secret at the same time.AzForm Component:
AzTextBox and AzForm entries support an enabled parameter. When disabled, the input is non-interactive and visual elements are dimmed.import { AzNavRail, AzNavItem, AzButtonShape, AzDockingSide } from '@HereLiesAz/aznavrail-react';
export default function App() {
const [expanded, setExpanded] = useState(false);
const items: AzNavItem[] = [
{
id: "home",
text: "Home",
isRailItem: true,
onClick: () => console.log("Home clicked"),
shape: AzButtonShape.CIRCLE,
},
{
id: "settings",
text: "Settings",
isRailItem: true,
onClick: () => console.log("Settings clicked"),
shape: AzButtonShape.RECTANGLE,
}
];
return (
<View style=>
<AzNavRail
appName="My App"
appIcon={require('./assets/icon.png')}
items={items}
expanded={expanded}
onToggleExpand={() => setExpanded(!expanded)}
settings=
/>
<View style=>
{/* Main Content */}
</View>
</View>
);
}
AzHostActivityLayout enforces a “Constitution” for your UI to ensure consistency and usability:
onscreen is automatically padded to avoid the rail, regardless of docking side or rotation.background(weight) to place content behind the rail (e.g., maps).azRailItem: Always visible.azMenuItem: Visible only in the drawer.azNestedRail: Opens a secondary popup rail (Vertical/Horizontal).azRailRelocItem: Draggable items for user reordering.Manage state directly in the rail without leaving the context.
azRailToggle / azMenuToggle.azRailCycler (multi-state buttons).AzNavRail(...) {
azAdvanced(
isLoading = true // Shows the AzLoad animation in the center of the screen
// ...
)
}
React Implementation:
import { AzNavItem } from '@HereLiesAz/aznavrail-react';
const items: AzNavItem[] = [
{
id: "power",
isRailItem: true,
isToggle: true,
isChecked: isPowerOn,
toggleOnText: "Power On",
toggleOffText: "Power Off",
onClick: () => setPowerOn(!isPowerOn),
// ...
},
{
id: "mode",
isRailItem: true,
isCycler: true,
options: ["Auto", "Cool", "Heat"],
selectedOption: currentMode,
// ...
}
];
You can also use AzLoad directly in your composables.
React Implementation:
import { AzLoad } from '@HereLiesAz/aznavrail-react';
<AzLoad size={48} color="#6200EE" />
The AzButton component (and AzToggle, AzCycler) can be used independently of the rail.
AzButton(
onClick = { /* ... */ },
text = "Save",
modifier = Modifier.fillMaxWidth(), // Now supports modifiers
shape = AzButtonShape.RECTANGLE,
enabled = true, // Can be disabled
isLoading = false, // Shows loading spinner without resizing button
contentPadding = PaddingValues(16.dp) // Custom padding
)
The AzRoller component is a versatile dropdown that behaves like a slot machine but also supports typing and filtering. It extends the functionality of AzTextBox with a unique split-click interaction model.
AzRoller(
options = listOf("Cherry", "Bell", "Bar"),
selectedOption = "Cherry",
onOptionSelected = { /* handle selection (String) */ },
hint = "Select Item",
enabled = true,
isError = false
)
React Implementation:
import { AzRoller } from '@HereLiesAz/aznavrail-react';
<AzRoller
options={["Cherry", "Bell", "Bar"]}
selectedOption="Cherry"
onOptionSelected={(option) => { /* handle selection */ }}
hint="Select Item"
enabled={true}
/>
AzNavRail supports hierarchical navigation with host and sub-items. This allows you to create nested menus that are easy to navigate.
React Implementation:
const items: AzNavItem[] = [
{
id: "host-1",
text: "Host Item",
isRailItem: true,
isHost: true,
isExpanded: isHost1Expanded,
onClick: () => setHost1Expanded(!isHost1Expanded),
// ...
},
{
id: "sub-1",
text: "Sub Item",
isRailItem: true,
isSubItem: true,
hostId: "host-1",
// ...
}
];
The rail can be detached and moved around the screen by long-pressing the header icon, which activates “FAB Mode”. To enable this feature, set enableRailDragging = true in the azAdvanced block.
React Implementation:
import { AzNavRailSettings } from '@HereLiesAz/aznavrail-react';
const settings: AzNavRailSettings = {
enableRailDragging: true
};
// Pass settings to AzNavRail
AzRailRelocItem is a specialized sub-item that users can reorder via drag-and-drop. This feature is supported on Android, Web, and React Native.
azRailRelocItem(
id = "reloc-1",
hostId = "host-1",
text = "Item 1",
forceHiddenMenuOpen = false, // Programmatically open the hidden menu!
onHiddenMenuDismiss = { /* Menu dismissed */ },
onRelocate = { from, to, newOrder ->
// Handle new order (List<String>)
}
) {
// Hidden Menu (Tap to select -> Long Press to open)
listItem("Action 1") { /* ... */ }
inputItem("Rename", initialValue = "Item 1") { newName -> /* ... */ }
}
React Implementation:
import { AzRailRelocItemProps, HiddenMenuScope } from '@HereLiesAz/aznavrail-react';
const relocItem: AzRailRelocItemProps = {
id: "reloc-1",
hostId: "host-1",
text: "Item 1",
isRailItem: false,
isSubItem: true,
forceHiddenMenuOpen: false,
onHiddenMenuDismiss: () => { /* Menu dismissed */ },
onRelocate: (fromIndex, toIndex, newOrder) => {
// Handle new order
},
hiddenMenu: (scope: HiddenMenuScope) => {
scope.listItem("Action 1", () => { /* ... */ });
scope.inputItem("Rename", "Item 1", (newName) => { /* ... */ });
}
};
// Pass this object within the items array to AzNavRail
AzNavRail can function as a system-wide overlay (using SYSTEM_ALERT_WINDOW). This allows users to access the navigation menu from anywhere on their device.
The expanded menu text font size (and the footer items text size) is strictly controlled by your app’s MaterialTheme.typography.titleLarge. To adjust the text size inside the side menu drawer, simply customize the titleLarge attribute in your app’s typography theme!
Navigation items support overriding their display text and colors when shown in the menu versus the rail using menuText, menuToggleOnText, menuToggleOffText, menuOptions, textColor, and fillColor properties! By default, the fillColor (translucent background) is automatically computed to be Black (with 25% opacity), unless the item’s main color is Black, in which case it is set to White (with 25% opacity) to ensure proper contrast.
React Implementation:
// Fonts and colors can be passed as props directly.
// The expanded menu text size can be handled via CSS or React Native styles
// depending on your implementation environment.
const settings: AzNavRailSettings = {
activeColor: '#6200EE'
};
const items: AzNavItem[] = [
{
id: "custom",
text: "Custom Color",
color: '#FF0000',
textColor: '#FFFFFF',
fillColor: 'rgba(255,0,0,0.25)',
// ...
}
];
The library includes a comprehensive Complete Guide (docs/AZNAVRAIL_COMPLETE_GUIDE.md) containing:
Copyright 2024 The AzNavRail Authors
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
AzNavRail features a powerful tutorial framework allowing you to script interactive scenes, dim the screen, and highlight specific items via an easy-to-use DSL. Tutorials are passed in azAdvanced or azSettings. When a tutorial is associated with an item ID, tapping that item’s Help card will launch the tutorial sequence.
import com.hereliesaz.aznavrail.tutorial.AzHighlight
import com.hereliesaz.aznavrail.tutorial.azTutorial
azAdvanced(
helpEnabled = true,
tutorials = mapOf(
"my-item-id" to azTutorial {
// A scene displays custom composable content underneath the tutorial overlay
scene(
id = "scene1",
content = {
Box(Modifier.fillMaxSize().background(Color.DarkGray)) {
Text("Scripted App Screen", color = Color.White)
}
}
) {
// Cards display textual instructions with next/skip actions
card(
title = "Welcome",
text = "Welcome to the tutorial.",
highlight = AzHighlight.FullScreen
)
card(
title = "Highlighting",
text = "Notice the highlighted item.",
highlight = AzHighlight.Item("my-item-id"),
actionText = "Finish"
)
}
}
)
)
React Implementation:
import { AzNavRailSettings } from '@HereLiesAz/aznavrail-react';
const settings: AzNavRailSettings = {
infoScreen: true,
helpList: {
"my-item-id": "This item has extended help information."
},
onDismissInfoScreen: () => { /* Handle dismissal */ }
};
// Pass settings to AzNavRail