Breadcrumb source

Inspect and copy the reviewed source included with this Free component.

Free source · 4 files

recipe.rs

// SPDX-FileCopyrightText: 2026 Proa Labs, Inc.
// SPDX-License-Identifier: MIT OR Apache-2.0

//! Breadcrumb recipe — static named slots for navigation hierarchy parts.

use crate::tw_join;
use proa_core::shared::attr_value::AttrValue;
use proa_core::{DataLoader, WebContext, WriteBuf, WriteError};

mod base {
    use super::*;

    pub const ROOT: &str = "";
    pub const LIST: &str = tw_join!(
        "flex",
        "flex-wrap",
        "items-center",
        "gap-1.5",
        "break-words",
        "text-sm",
        "text-muted-foreground",
        "sm:gap-2.5"
    );
    pub const ITEM: &str = tw_join!("inline-flex", "items-center", "gap-1.5");
    pub const LINK: &str = tw_join!("transition-colors", "hover:text-foreground");
    pub const PAGE: &str = tw_join!("font-normal", "text-foreground");
    pub const SEPARATOR: &str = tw_join!("[&>svg]:h-3.5", "[&>svg]:w-3.5");
    pub const ELLIPSIS: &str = tw_join!("flex", "h-9", "w-9", "items-center", "justify-center");
    pub const ELLIPSIS_LABEL: &str = "sr-only";
}

/// Optional inputs accepted by [`BreadcrumbRecipe::resolve`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct BreadcrumbRecipeProps;

/// Static named classes for every Breadcrumb part.
#[derive(Debug, Clone, Copy)]
pub struct BreadcrumbRecipe {
    pub root: &'static str,
    pub list: &'static str,
    pub item: &'static str,
    pub link: &'static str,
    pub page: &'static str,
    pub separator: &'static str,
    pub ellipsis: &'static str,
    pub ellipsis_label: &'static str,
}

impl BreadcrumbRecipe {
    pub const fn resolve(&'static self, _props: BreadcrumbRecipeProps) -> BreadcrumbStyle {
        BreadcrumbStyle { recipe: self }
    }
}

/// Fully resolved, streamable Breadcrumb root style.
#[must_use]
#[derive(Debug, Clone, Copy)]
pub struct BreadcrumbStyle {
    recipe: &'static BreadcrumbRecipe,
}

impl AttrValue for BreadcrumbStyle {
    #[inline(always)]
    fn should_render(&self) -> bool {
        !self.recipe.root.is_empty()
    }

    #[inline(always)]
    fn render_attr_value<B: WriteBuf, L: DataLoader>(
        &self,
        cx: &mut WebContext<L, B>,
    ) -> Result<(), WriteError> {
        cx.out.extend_static(self.recipe.root.as_bytes())
    }
}

pub const BREADCRUMB_RECIPE: BreadcrumbRecipe = BreadcrumbRecipe {
    root: base::ROOT,
    list: base::LIST,
    item: base::ITEM,
    link: base::LINK,
    page: base::PAGE,
    separator: base::SEPARATOR,
    ellipsis: base::ELLIPSIS,
    ellipsis_label: base::ELLIPSIS_LABEL,
};

pub const fn breadcrumb_recipe() -> &'static BreadcrumbRecipe {
    &BREADCRUMB_RECIPE
}

impl crate::variant_spec::ComponentSpec for BreadcrumbRecipe {
    const NAME: &'static str = "Breadcrumb";

    fn base_classes(&self) -> &'static str {
        self.root
    }

    fn variant_metadata(&self) -> Vec<crate::variant_spec::VariantMetadata> {
        Vec::new()
    }

    fn anatomy(&self) -> Option<crate::Anatomy> {
        Some(super::BREADCRUMB_ANATOMY)
    }
}

/// Compatibility accessors for the former standalone helpers.
pub const fn breadcrumb_classes() -> &'static str {
    BREADCRUMB_RECIPE.root
}

pub const fn breadcrumb_list_classes() -> &'static str {
    BREADCRUMB_RECIPE.list
}

pub const fn breadcrumb_item_classes() -> &'static str {
    BREADCRUMB_RECIPE.item
}

pub const fn breadcrumb_link_classes() -> &'static str {
    BREADCRUMB_RECIPE.link
}

pub const fn breadcrumb_page_classes() -> &'static str {
    BREADCRUMB_RECIPE.page
}

pub const fn breadcrumb_separator_classes() -> &'static str {
    BREADCRUMB_RECIPE.separator
}

pub const fn breadcrumb_ellipsis_classes() -> &'static str {
    BREADCRUMB_RECIPE.ellipsis
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn recipe_exposes_every_named_slot() {
        let recipe = breadcrumb_recipe();
        assert!(recipe.root.is_empty());
        assert!(recipe.list.contains("flex-wrap"));
        assert!(recipe.item.contains("inline-flex"));
        assert!(recipe.link.contains("hover:text-foreground"));
        assert!(recipe.page.contains("text-foreground"));
        assert!(recipe.separator.contains("[&>svg]:h-3.5"));
        assert!(recipe.ellipsis.contains("justify-center"));
        assert_eq!(recipe.ellipsis_label, "sr-only");
    }

    #[test]
    fn recipe_is_const_and_copy() {
        const STYLE: BreadcrumbStyle = BREADCRUMB_RECIPE.resolve(BreadcrumbRecipeProps);
        let copied = STYLE;
        assert!(copied.recipe.root.is_empty());
    }

    #[test]
    fn recipe_metadata_exposes_the_complete_anatomy() {
        let metadata = crate::variant_spec::component_metadata(breadcrumb_recipe());
        let anatomy = metadata.anatomy.as_ref().unwrap();
        assert_eq!(metadata.name, "Breadcrumb");
        assert!(metadata.variants.is_empty());
        assert_eq!(anatomy.scope, "breadcrumb");
        assert_eq!(anatomy.parts, super::super::BREADCRUMB_ANATOMY.parts());
        metadata.validate().unwrap();
    }
}

Copy this source with the Free Proa UI components it imports; those component files remain available from their own source pages.

Licensed under MIT OR Apache-2.0. Third-party notices remain attached to the installed payload.

Open Markdown
FreeBreadcrumb

Page hierarchy navigation.

Install with the Proa CLI
proa ui add breadcrumb

Installs the reviewed component source, dependencies, shared support files, and required legal notices.

CLI and registry setup
recipe.rs
// SPDX-FileCopyrightText: 2026 Proa Labs, Inc.
// SPDX-License-Identifier: MIT OR Apache-2.0

//! Breadcrumb recipe — static named slots for navigation hierarchy parts.

use crate::tw_join;
use proa_core::shared::attr_value::AttrValue;
use proa_core::{DataLoader, WebContext, WriteBuf, WriteError};

mod base {
    use super::*;

    pub const ROOT: &str = "";
    pub const LIST: &str = tw_join!(
        "flex",
        "flex-wrap",
        "items-center",
        "gap-1.5",
        "break-words",
        "text-sm",
        "text-muted-foreground",
        "sm:gap-2.5"

Search

Type at least 2 characters

Customize

Make it yours

Palette

Radius

Overview
Components
Settings

Build your own

Themed Proa UI surface

Preview
Components52
RecipesTyped
customer-portal