Breadcrumb
The trail of pages above the one on screen, each a link back to it, ending in the page on screen.
import com.pantrixui.components.navigation.breadcrumb.PantrixBreadcrumb
- Links and the page on screen. The pages above are links, each underlined; when one is pressed,
onSelectreports its key. The last page is the page on screen: it is a text, it is not pressed, and its key is never reported. - It folds by itself. Where the row is too narrow, the trail keeps its first page and its last ones, and those between them go into the menu that the three-dot button opens. Where the first page and the last do not fit beside the button either, the long names are cut to one width, and a short one stays as it is.
- The most pages. With
maxItemsthe row shows no more pages than that, even where it has room. It has to be at least two: a trail always shows its first page and its last. - Icons.
BreadcrumbItem.iconstands before the page's name; withiconOnlyit takes the name's place, and the page is a button that says its name to a screen reader. - Type and sizes.
textStyleis the names' type, the theme'slabelwhere it is not given.BreadcrumbStylegives the room between the names and the marks, and the size of the mark and of the icon; these are the same on every platform.minHeightmakes the row lower than the touch target, andlinkUnderlinesays when the links are underlined. - Colours.
BreadcrumbColorspaints the links, the page on screen and the marks one by one. On a fill, all of a trail that is given no colour is in the colour that is written on the fill. - Right to left. In languages read from right to left the trail starts on the right, and the marks turn round.
- Automation. In a trail that is given a
tagKey, the pages and the button for the folded pages are named inside it:Breadcrumb_docs.Item_components,Breadcrumb_docs.More_pages.
Examples
Navigating folders
At its plainest: the trail's pages (items) and what happens when one of them is pressed (onSelect). Which page the app is on is the screen's state; the trail does not hold it, and only reports the key of the page that was pressed.
Press a folder above: the app goes up to it, and the trail ends in that folder. "Go deeper" makes the path longer again. The last page is not pressed: that is where the app already is.
var depth by rememberSaveable { mutableIntStateOf(FOLDERS.size) }
PantrixBreadcrumb(
items = FOLDERS.take(depth),
onSelect = { key -> depth = FOLDERS.indexOfFirst { it.key == key } + 1 },
tagKey = "folders"
)
FolderControls(depth = depth, onDeeper = { depth++ }, tagKey = "folders_deeper")
private val FOLDERS = listOf(
BreadcrumbItem(key = "home", label = "Home"),
BreadcrumbItem(key = "documents", label = "Documents"),
BreadcrumbItem(key = "projects", label = "Projects"),
BreadcrumbItem(key = "pantrix", label = "Pantrix"),
BreadcrumbItem(key = "design", label = "Design")
)
@Composable
private fun FolderControls(
depth: Int,
onDeeper: () -> Unit,
tagKey: String
) {
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalAlignment = Alignment.CenterVertically
) {
PantrixButton(
text = "Go deeper",
onClick = onDeeper,
variant = ButtonVariant.Soft,
size = ButtonSize.Small,
enabled = depth < FOLDERS.size,
tagKey = tagKey
)
PantrixText(text = "You are here: ${FOLDERS[depth - 1].label}", color = PantrixTheme.colors.textSecondary)
}
}
A row that shows three pages at the most
maxItems = 3: the row shows no more than three pages, even where it has room. The first page and the last two stay; those between them are behind the three-dot button.
Press the button: the folded folders open as a menu, in the order of the trail. A folder chosen in the menu is reported through onSelect as one pressed in the row is, and the app goes up to it. When the path is down to three pages the button goes.
var depth by rememberSaveable { mutableIntStateOf(FOLDERS.size) }
PantrixBreadcrumb(
items = FOLDERS.take(depth),
onSelect = { key -> depth = FOLDERS.indexOfFirst { it.key == key } + 1 },
maxItems = 3,
tagKey = "folded"
)
FolderControls(depth = depth, onDeeper = { depth++ }, tagKey = "folded_deeper")
@Composable
private fun FolderControls(
depth: Int,
onDeeper: () -> Unit,
tagKey: String
) {
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalAlignment = Alignment.CenterVertically
) {
PantrixButton(
text = "Go deeper",
onClick = onDeeper,
variant = ButtonVariant.Soft,
size = ButtonSize.Small,
enabled = depth < FOLDERS.size,
tagKey = tagKey
)
PantrixText(text = "You are here: ${FOLDERS[depth - 1].label}", color = PantrixTheme.colors.textSecondary)
}
}
private val FOLDERS = listOf(
BreadcrumbItem(key = "home", label = "Home"),
BreadcrumbItem(key = "documents", label = "Documents"),
BreadcrumbItem(key = "projects", label = "Projects"),
BreadcrumbItem(key = "pantrix", label = "Pantrix"),
BreadcrumbItem(key = "design", label = "Design")
)
Icons: before the name or in its place
icon stands before the page's name, in the name's colour. The icon and the name are one link: a press on the icon is a press on the name, and the icon is no second stop for the keyboard and no second thing for a screen reader.
In the first trail the first page is shown by its icon alone, with iconOnly: it is a button that says its name to a screen reader. A page without an icon is written by its name whatever iconOnly says.
In the second trail two pages that are shown by their icons alone are folded away. Press the three-dot button: the menu writes each page's name beside its icon.
PantrixBreadcrumb(
items = listOf(
BreadcrumbItem(key = "files", label = "Files", icon = PantrixIcons.Folder, iconOnly = true),
BreadcrumbItem(key = "starred", label = "Starred", icon = PantrixIcons.Star),
BreadcrumbItem(key = "schedule", label = "Calendar", icon = PantrixIcons.Calendar)
),
onSelect = {},
tagKey = "icons"
)
PantrixBreadcrumb(
items = listOf(
BreadcrumbItem(key = "files", label = "Files", icon = PantrixIcons.Folder, iconOnly = true),
BreadcrumbItem(key = "starred", label = "Starred", icon = PantrixIcons.Star, iconOnly = true),
BreadcrumbItem(key = "schedule", label = "Calendar", icon = PantrixIcons.Calendar, iconOnly = true),
BreadcrumbItem(key = "today", label = "Today")
),
onSelect = {},
maxItems = 2,
tagKey = "icons_folded"
)
A path too long for its row folds by itself
No maxItems is given: the trail folds to the width that is left to it. First the pages after the first go behind the button, as few of them as it takes; the trail keeps its first page, where it began, and its last ones, where it is. Where the first page and the last do not fit beside the button either, the long names are cut to one width, and a short one stays as it is.
The same path at three widths: the first as wide as the example, the others in frames 480dp and 240dp wide at the most. In the middle frame the page in between is behind the button; in the narrow frame the last page's name is cut as well. Narrow the window: the first trail folds in the same order.
PantrixBreadcrumb(items = LONG_PATH, onSelect = {}, tagKey = "long")
PantrixSurface(modifier = Modifier.width(480.dp), border = PantrixTheme.colors.divider) {
PantrixBreadcrumb(
items = LONG_PATH,
onSelect = {},
modifier = Modifier.padding(horizontal = PantrixTheme.spacing.md),
tagKey = "long_medium"
)
}
PantrixSurface(modifier = Modifier.width(240.dp), border = PantrixTheme.colors.divider) {
PantrixBreadcrumb(
items = LONG_PATH,
onSelect = {},
modifier = Modifier.padding(horizontal = PantrixTheme.spacing.md),
tagKey = "long_narrow"
)
}
private val LONG_PATH = listOf(
BreadcrumbItem(key = "home", label = "Home"),
BreadcrumbItem(key = "systems", label = "Design systems and component libraries"),
BreadcrumbItem(key = "navigation", label = "Navigation for wide and narrow windows")
)
On a fill
A trail on a fill that is not one of the theme's grounds. No colour is given: the fill says what is written on it, and all of the trail, its links, the page on screen and the marks, is written in that colour. The theme's link and text colours are for the theme's own grounds; here a link is told from the page on screen by its underline.
PantrixSurface(
modifier = Modifier.fillMaxWidth(),
color = PantrixTheme.colors.primary.color,
shape = PantrixTheme.shapes.md
) {
PantrixBreadcrumb(
items = FOLDERS,
onSelect = {},
modifier = Modifier.padding(horizontal = PantrixTheme.spacing.md),
maxItems = 3,
tagKey = "filled"
)
}
private val FOLDERS = listOf(
BreadcrumbItem(key = "home", label = "Home"),
BreadcrumbItem(key = "documents", label = "Documents"),
BreadcrumbItem(key = "projects", label = "Projects"),
BreadcrumbItem(key = "pantrix", label = "Pantrix"),
BreadcrumbItem(key = "design", label = "Design")
)
Text style and sizes
textStyle is the type the names are set in: a trail that is given none is written in the theme's label style. style gives the sizes: itemGap is the room between a name and the mark beside it, and between an icon and its name; separatorSize is the size of the mark and of the button for the folded pages; iconSize is the size of a page's own icon. Only the fields that are set change.
The middle trail is as it is with nothing given: 16dp marks and icons, 4dp from the names. The one above it is the same trail set small, and the one below it the same trail set large. The rows of all three are at least as tall as the platform's touch target.
PantrixBreadcrumb(
items = PLACES,
onSelect = {},
textStyle = PantrixTheme.typography.footnote,
style = BreadcrumbStyle(itemGap = 2.dp, separatorSize = 12.dp, iconSize = 12.dp),
tagKey = "small"
)
PantrixBreadcrumb(items = PLACES, onSelect = {}, tagKey = "usual")
PantrixBreadcrumb(
items = PLACES,
onSelect = {},
textStyle = PantrixTheme.typography.callout,
style = BreadcrumbStyle(itemGap = 8.dp, separatorSize = 20.dp, iconSize = 20.dp),
tagKey = "large"
)
private val PLACES = listOf(
BreadcrumbItem(key = "files", label = "Files", icon = PantrixIcons.Folder),
BreadcrumbItem(key = "starred", label = "Starred", icon = PantrixIcons.Star),
BreadcrumbItem(key = "schedule", label = "Calendar", icon = PantrixIcons.Calendar)
)
Over a title, low and without lines
The trail over a documentation page's title: as low as a line of text, and not underlined. minHeight is the row's least height; where it is not given, it is the platform's touch target. In a lower row a touch beside a page still reaches it: the theme gives a small target room for a touch that takes no room in the layout.
linkUnderline = LinkUnderline.OnHover underlines the links only under a pointer and while they hold the focus: a trail does not stand in a sentence, and its marks already tell its links from the page on screen. Where the platform is used by touch they are still underlined always.
Column {
PantrixBreadcrumb(
items = PLACES,
onSelect = {},
textStyle = PantrixTheme.typography.footnote,
style = BreadcrumbStyle(minHeight = 20.dp, linkUnderline = LinkUnderline.OnHover),
tagKey = "over_a_title"
)
PantrixText(text = PLACES.last().label, style = PantrixTheme.typography.headline)
}
private val PLACES = listOf(
BreadcrumbItem(key = "files", label = "Files", icon = PantrixIcons.Folder),
BreadcrumbItem(key = "starred", label = "Starred", icon = PantrixIcons.Star),
BreadcrumbItem(key = "schedule", label = "Calendar", icon = PantrixIcons.Calendar)
)
With its own colours, a small type and small marks
colors takes the colour of the links (link), of the page on screen (current) and of the marks (separator) one by one; one that is left out stays the theme's. Here the links and the marks are in the app's own purple, which is in none of the theme's roles; the page on screen is given no colour, and stays in the theme's text colour.
The type is footnote, and the marks are 12dp and 6dp from the names: the colour, the text style and the sizes are given independently of each other.
val own = ownColors()
PantrixBreadcrumb(
items = FOLDERS.take(3),
onSelect = {},
textStyle = PantrixTheme.typography.footnote,
style = BreadcrumbStyle(itemGap = 6.dp, separatorSize = 12.dp),
colors = BreadcrumbColors(link = own.color, separator = own.color),
tagKey = "own"
)
private val FOLDERS = listOf(
BreadcrumbItem(key = "home", label = "Home"),
BreadcrumbItem(key = "documents", label = "Documents"),
BreadcrumbItem(key = "projects", label = "Projects"),
BreadcrumbItem(key = "pantrix", label = "Pantrix"),
BreadcrumbItem(key = "design", label = "Design")
)
API
items
The trail of pages above the one on screen, each a link back to it, ending in the page on screen.
| Parameter | Type | Default | What it is |
|---|---|---|---|
items | List<BreadcrumbItem> | the trail from its top, ending in the page on screen. | |
onSelect | (key: String) -> Unit | told the key of a page that is pressed, in the row or in the menu: never the last one's, which is where the app is. | |
modifier | Modifier | Modifier | applied to the row. |
maxItems | Int | Int.MAX_VALUE | the most pages the row shows, whatever room it has: at least two. |
textStyle | TextStyle | PantrixTheme.typography.label | the type the pages are set in: the theme's label unless given. |
style | BreadcrumbStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform. |
colors | BreadcrumbColors? | null | this call's own colours. Only the ones it sets change; the rest stay the theme's. |
tagKey | String? | null | a locale-independent key for automation: the row's tag is Breadcrumb_<tagKey>, and its pages and the button that shows the folded ones are named inside it, Breadcrumb_<tagKey>.Item_<page's key> and Breadcrumb_<tagKey>.More_pages. The menu is Menu_<tagKey>_more, with a row for each folded page. |
BreadcrumbStyle
PantrixBreadcrumb's geometry: the room between a page and the mark beside it, how large that mark is, and how large a page's own icon is. It is the same on every platform: a trail of pages is a line of text, with 16dp marks and icons 4dp from the words. The room follows the density; the mark and the icon do not.
| Parameter | Type | Default | What it is |
|---|---|---|---|
itemGap | Dp | Dp.Unspecified | Between a page's name and the mark that parts it from the next, and between a page's icon and its name. |
separatorSize | Dp | Dp.Unspecified | The mark between two pages, and the button that stands for the pages a trail has folded. |
iconSize | Dp | Dp.Unspecified | A page's own icon, before its name or in its place. |
minHeight | Dp | Dp.Unspecified | The least height of the trail's row: the platform's touch target where it is not set, so that nothing else lies under a touch beside a page. A lower one fits a trail to a line of text over a page's title; a touch beside a page still reaches it, as the theme gives a small target its room for a touch without room in the layout. |
linkUnderline | LinkUnderline? | null | When the pages above the one on screen are underlined: Always where it is not set. A trail stands apart from any sentence, and its marks tell its links from the page on screen as well: LinkUnderline.OnHover underlines them under a pointer and the keyboard's focus, and always under a finger. |
BreadcrumbColors
What a PantrixBreadcrumb is painted with, for a trail that does not take the theme's colours: a colour that is set is used, and one that is left out stays the theme's.
| Parameter | Type | Default | What it is |
|---|---|---|---|
link | Color | Color.Unspecified | The pages above the one on screen, which are links, and their icons. The primary role's color. |
current | Color | Color.Unspecified | The page on screen, the trail's last, and its icon. The theme's textPrimary. |
separator | Color | Color.Unspecified | The marks between two pages, and the button that shows the pages a long trail has folded away. The theme's textSecondary. |
Accessibility
- Screen reader. The row is a group named "Breadcrumb", the last page is read with the state "Current page", and the marks in between are not read. On iOS the group has no name: a screen reader there reads a group's name after what the group holds.