diff --git a/apps/web/content/docs/components/bottom-navigation.mdx b/apps/web/content/docs/components/bottom-navigation.mdx
new file mode 100644
index 000000000..017fe36c9
--- /dev/null
+++ b/apps/web/content/docs/components/bottom-navigation.mdx
@@ -0,0 +1,36 @@
+---
+title: React Bottom Navigation - Flowbite
+description: Use the bottom navigation bar component to allow users to navigate through your website or create a control bar using a menu that is positioned at the bottom of the page
+---
+
+The bottom bar component can be used to allow menu items and certain control actions to be performed by the user through the use of a fixed bar positioning on the bottom side of your page.
+
+Check out multiple examples of the bottom navigation component based on various styles, controls, sizes, content and leverage the utility classes from Tailwind CSS to integrate into your own project.
+
+## Default bottom navigation
+
+Use the default bottom navigation bar example to show a list of menu items as buttons to allow the user to navigate through your website based on a fixed position. You can also use anchor tags instead of buttons.
+
+
+
+## Menu items with border
+
+This example can be used to show a border between the menu items inside the bottom navigation bar.
+
+
+
+## Example with Tooltip
+
+This example can be used to show a Tooltip on the hover on the menu items.
+
+
+
+## Theme
+
+To learn more about how to customize the appearance of components, please see the [Theme docs](/docs/customize/theme).
+
+
+
+## References
+
+- [Flowbite Bottom Navigation](https://flowbite.com/docs/components/bottom-navigation/)
diff --git a/apps/web/data/components.tsx b/apps/web/data/components.tsx
index 29e7e8619..60e64a825 100644
--- a/apps/web/data/components.tsx
+++ b/apps/web/data/components.tsx
@@ -35,6 +35,13 @@ export const COMPONENTS_DATA: Component[] = [
link: "/docs/components/badge",
classes: "w-28",
},
+ {
+ name: "Bottom Navigation",
+ image: "/images/components/bottom-bar.svg",
+ imageDark: "/images/components/bottom-bar-dark.svg",
+ link: `/docs/components/bottom-navigation`,
+ classes: "w-28",
+ },
{
name: "Breadcrumbs",
image: "/images/components/breadcrumbs.svg",
diff --git a/apps/web/data/docs-sidebar.ts b/apps/web/data/docs-sidebar.ts
index 60c49560b..845bdf3ed 100644
--- a/apps/web/data/docs-sidebar.ts
+++ b/apps/web/data/docs-sidebar.ts
@@ -58,6 +58,7 @@ export const DOCS_SIDEBAR: DocsSidebarSection[] = [
{ title: "Avatar", href: "/docs/components/avatar" },
{ title: "Badge", href: "/docs/components/badge" },
{ title: "Banner", href: "/docs/components/banner", isNew: true },
+ { title: "Bottom Navigation", href: "/docs/components/bottom-navigation", isNew: true },
{ title: "Breadcrumb", href: "/docs/components/breadcrumb" },
{ title: "Button", href: "/docs/components/button" },
{ title: "Button group", href: "/docs/components/button-group" },
diff --git a/apps/web/examples/bottomNavigation/bottomNavigation.root.tsx b/apps/web/examples/bottomNavigation/bottomNavigation.root.tsx
new file mode 100644
index 000000000..410f116e3
--- /dev/null
+++ b/apps/web/examples/bottomNavigation/bottomNavigation.root.tsx
@@ -0,0 +1,56 @@
+"use client";
+
+import { BottomNavigation } from "flowbite-react";
+import { AiFillHome } from "react-icons/ai";
+import { CgProfile } from "react-icons/cg";
+import { GiSettingsKnobs, GiWallet } from "react-icons/gi";
+import type { CodeData } from "~/components/code-demo";
+
+const code = `
+"use client";
+
+import { BottomNavigation } from "flowbite-react";
+
+function Component() {
+ return (
+
+
+
+
+
+
+ )
+}
+`;
+
+function Component() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export const root: CodeData = {
+ type: "single",
+ code: [
+ {
+ fileName: "client",
+ language: "tsx",
+ code,
+ },
+ ],
+ githubSlug: "bottomNavigation/bottomNavigation.root.tsx",
+ component: ,
+};
diff --git a/apps/web/examples/bottomNavigation/bottomNavigation.withBorder.tsx b/apps/web/examples/bottomNavigation/bottomNavigation.withBorder.tsx
new file mode 100644
index 000000000..2123a7dc0
--- /dev/null
+++ b/apps/web/examples/bottomNavigation/bottomNavigation.withBorder.tsx
@@ -0,0 +1,57 @@
+"use client";
+
+import { BottomNavigation } from "flowbite-react";
+import { AiFillHome } from "react-icons/ai";
+import { CgProfile } from "react-icons/cg";
+import { GiSettingsKnobs, GiWallet } from "react-icons/gi";
+import type { CodeData } from "~/components/code-demo";
+
+const code = `
+"use client";
+
+import { BottomNavigation } from "flowbite-react";
+
+function Component() {
+ return (
+
+
+
+
+
+
+ )
+}
+`;
+
+function Component() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export const withBorder: CodeData = {
+ type: "single",
+ code: [
+ {
+ fileName: "client",
+ language: "tsx",
+ code,
+ },
+ ],
+ githubSlug: "bottomNavigation/bottomNavigation.withBorder.tsx",
+ component: ,
+};
diff --git a/apps/web/examples/bottomNavigation/bottomNavigation.withTooltip.tsx b/apps/web/examples/bottomNavigation/bottomNavigation.withTooltip.tsx
new file mode 100644
index 000000000..814e73cab
--- /dev/null
+++ b/apps/web/examples/bottomNavigation/bottomNavigation.withTooltip.tsx
@@ -0,0 +1,56 @@
+"use client";
+
+import { BottomNavigation } from "flowbite-react";
+import { AiFillHome } from "react-icons/ai";
+import { CgProfile } from "react-icons/cg";
+import { GiSettingsKnobs, GiWallet } from "react-icons/gi";
+import type { CodeData } from "~/components/code-demo";
+
+const code = `
+"use client";
+
+import { BottomNavigation } from "flowbite-react";
+
+function Component() {
+ return (
+
+
+
+
+
+
+ )
+}
+`;
+
+function Component() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export const withTooltip: CodeData = {
+ type: "single",
+ code: [
+ {
+ fileName: "client",
+ language: "tsx",
+ code,
+ },
+ ],
+ githubSlug: "bottomNavigation/bottomNavigation.withTooltip.tsx",
+ component: ,
+};
diff --git a/apps/web/examples/bottomNavigation/index.ts b/apps/web/examples/bottomNavigation/index.ts
new file mode 100644
index 000000000..90c719c40
--- /dev/null
+++ b/apps/web/examples/bottomNavigation/index.ts
@@ -0,0 +1,3 @@
+export { root } from "./bottomNavigation.root";
+export { withBorder } from "./bottomNavigation.withBorder";
+export { withTooltip } from "./bottomNavigation.withTooltip";
diff --git a/apps/web/examples/index.ts b/apps/web/examples/index.ts
index 7992d8e29..9ab67830f 100644
--- a/apps/web/examples/index.ts
+++ b/apps/web/examples/index.ts
@@ -4,6 +4,7 @@ export * as avatar from "./avatar";
export * as badge from "./badge";
export * as banner from "./banner";
export * as blockquote from "./blockquote";
+export * as bottomNavigation from "./bottomNavigation";
export * as breadcrumb from "./breadcrumb";
export * as button from "./button";
export * as buttonGroup from "./buttonGroup";
diff --git a/apps/web/public/images/components/bottom-bar-dark.svg b/apps/web/public/images/components/bottom-bar-dark.svg
new file mode 100644
index 000000000..0a0f67895
--- /dev/null
+++ b/apps/web/public/images/components/bottom-bar-dark.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/public/images/components/bottom-bar.svg b/apps/web/public/images/components/bottom-bar.svg
new file mode 100644
index 000000000..9e0dfc0bb
--- /dev/null
+++ b/apps/web/public/images/components/bottom-bar.svg
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/BottomNavigation/BottomNavigation.spec.tsx b/packages/ui/src/components/BottomNavigation/BottomNavigation.spec.tsx
new file mode 100644
index 000000000..7438925ba
--- /dev/null
+++ b/packages/ui/src/components/BottomNavigation/BottomNavigation.spec.tsx
@@ -0,0 +1,134 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import { BottomNavigation } from "./BottomNavigation";
+
+describe.concurrent("BottomNavigation", () => {
+ it('BottomNavigation should have "data-testid=flowbite-bottom-navigation" in the document', async () => {
+ render( );
+
+ bottomNavTestId().forEach((bottomNavTestId) => {
+ expect(bottomNavTestId).toBeInTheDocument();
+ });
+ });
+
+ it('BottomNavigation.Item should have "data-testid=flowbite-bottom-nav-item" in the document', async () => {
+ render( );
+
+ bottomNavItemTestId().forEach((bottomNavItemTest) => {
+ expect(bottomNavItemTest).toBeInTheDocument();
+ });
+ });
+
+ it('BottomNavigation.Item should have "button" in the document', async () => {
+ render( );
+
+ bottomNavItemButton().forEach((button) => {
+ expect(button).toBeInTheDocument();
+ });
+ });
+
+ it('BottomNavigation.Item should have "Home" in the document', async () => {
+ render( );
+
+ homeTextInButton().forEach((homeText) => {
+ expect(homeText).toBeInTheDocument();
+ });
+ });
+
+ it('should have "attribute of type = button" in the document', async () => {
+ render( );
+
+ bottomNavItemTestId().forEach((buttonType) => {
+ expect(buttonType).toHaveAttribute("type", "button");
+ });
+ });
+
+ it("tooltip in document", async () => {
+ render( );
+
+ expect(tooltips()).toBeInTheDocument();
+ });
+
+ it('svg icons in the document by "data-testid=flowbite-bottom-nav-icon"', async () => {
+ render( );
+
+ imgByTestId().forEach((imgTestId) => {
+ expect(imgTestId).toBeInTheDocument();
+ });
+ });
+
+ it("first svg Icon in the Tooltip", async () => {
+ render( );
+
+ expect(imgByTestId()[0]).toBeInTheDocument();
+ });
+
+ it("second svg Icon in the Tooltip", async () => {
+ render( );
+
+ expect(imgByTestId()[1]).toBeInTheDocument();
+ });
+
+ it("third svg Icon outside of Tooltip", async () => {
+ render( );
+
+ expect(imgByTestId()[2] as HTMLElement).toBeInTheDocument();
+ });
+
+ it("all svg Icon should have className of w-5", async () => {
+ render( );
+
+ imgByTestId().forEach((imgByTest) => {
+ expect(imgByTest).toHaveClass("w-5");
+ });
+ });
+
+ it('first svg element selector using "document.querySelector=svg"', async () => {
+ render( );
+
+ const svgImg = document.querySelectorAll("svg")[0] as SVGElement;
+
+ expect(svgImg).toBeInTheDocument();
+ });
+
+ it('second svg element selector using "document.querySelector=svg"', async () => {
+ render( );
+
+ const svgImg = document.querySelectorAll("svg")[1] as SVGElement;
+
+ expect(svgImg).toBeInTheDocument();
+ });
+
+ it('third svg element selector using "document.querySelector=svg"', async () => {
+ render( );
+
+ const svgImg = document.querySelectorAll("svg")[2] as SVGElement;
+
+ expect(svgImg).toBeInTheDocument();
+ });
+});
+
+const bottomNavTestId = () => screen.getAllByTestId("flowbite-bottom-navigation");
+const bottomNavItemTestId = () => screen.getAllByTestId("flowbite-bottom-nav-item");
+const bottomNavItemButton = () => screen.getAllByRole("button");
+const homeTextInButton = () => screen.getAllByText("Home");
+const tooltips = () => screen.getByTestId("flowbite-tooltip");
+const imgByTestId = () => screen.getAllByTestId("flowbite-bottom-nav-icon");
+
+const TestBottomNavigation = (): JSX.Element => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/BottomNavigation/BottomNavigation.stories.tsx b/packages/ui/src/components/BottomNavigation/BottomNavigation.stories.tsx
new file mode 100644
index 000000000..71fa1e496
--- /dev/null
+++ b/packages/ui/src/components/BottomNavigation/BottomNavigation.stories.tsx
@@ -0,0 +1,47 @@
+import type { Meta, StoryFn } from "@storybook/react";
+import { AiFillHome } from "react-icons/ai";
+import { GiWallet } from "react-icons/gi";
+import { BottomNavigation, type BottomNavigationProps } from "./BottomNavigation";
+
+export default {
+ title: "Components/BottomNavigation",
+ component: BottomNavigation,
+} as Meta;
+
+const Template: StoryFn = (args) => (
+
+
+
+);
+
+export const DefaultBottomNav = Template.bind({});
+DefaultBottomNav.storyName = "Default";
+DefaultBottomNav.args = {
+ children: (
+ <>
+
+
+ >
+ ),
+};
+
+export const WithBorder = Template.bind({});
+WithBorder.args = {
+ children: (
+ <>
+
+
+ >
+ ),
+ bordered: true,
+};
+
+export const WithTooltip = Template.bind({});
+WithTooltip.args = {
+ children: (
+ <>
+
+
+ >
+ ),
+};
diff --git a/packages/ui/src/components/BottomNavigation/BottomNavigation.tsx b/packages/ui/src/components/BottomNavigation/BottomNavigation.tsx
new file mode 100644
index 000000000..638f963c2
--- /dev/null
+++ b/packages/ui/src/components/BottomNavigation/BottomNavigation.tsx
@@ -0,0 +1,45 @@
+"use client";
+
+import type { ComponentProps, FC } from "react";
+import { twMerge } from "tailwind-merge";
+import { mergeDeep } from "../../helpers/merge-deep";
+import { getTheme } from "../../theme-store";
+import type { DeepPartial } from "../../types";
+import type { FlowbiteBoolean } from "../Flowbite";
+import { BottomNavigationItem, type FlowbiteBottomNavigationItemTheme } from "./BottomNavigationItem";
+
+export interface FlowbiteBottomNavigationTheme {
+ root: {
+ base: string;
+ inner: string;
+ };
+ border: FlowbiteBoolean;
+ item: FlowbiteBottomNavigationItemTheme;
+}
+
+export interface BottomNavigationProps extends ComponentProps<"div"> {
+ bordered?: boolean;
+ theme?: DeepPartial;
+}
+
+const BottomNavigationComponent: FC = ({
+ children,
+ bordered: isBordered = false,
+ theme: customTheme = {},
+ className,
+ ...props
+}) => {
+ const theme = mergeDeep(getTheme().bottomNavigation, customTheme);
+
+ return (
+
+ );
+};
+
+BottomNavigationComponent.displayName = "BottomNavigation";
+
+export const BottomNavigation = Object.assign(BottomNavigationComponent, {
+ Item: BottomNavigationItem,
+});
diff --git a/packages/ui/src/components/BottomNavigation/BottomNavigationItem.tsx b/packages/ui/src/components/BottomNavigation/BottomNavigationItem.tsx
new file mode 100644
index 000000000..aa8bc4920
--- /dev/null
+++ b/packages/ui/src/components/BottomNavigation/BottomNavigationItem.tsx
@@ -0,0 +1,104 @@
+"use client";
+
+import type { ComponentProps, FC } from "react";
+import { useId } from "react";
+import { IoMdHome } from "react-icons/io";
+import { twMerge } from "tailwind-merge";
+import { mergeDeep } from "../../helpers/merge-deep";
+import { getTheme } from "../../theme-store";
+import type { DeepPartial } from "../../types";
+import { Tooltip } from "../Tooltip";
+
+export interface FlowbiteBottomNavigationItemTheme {
+ base: string;
+ icon: {
+ base: string;
+ };
+ label: string;
+}
+
+export interface BottomNavigationItemProps extends Omit, "ref">, Record {
+ icon?: FC>;
+ label: string;
+ theme?: DeepPartial;
+ showTooltip?: boolean;
+ showLabel?: boolean;
+}
+
+interface BottomNavItemBtnProps {
+ reactId: string;
+ customClassName: string;
+ icon: FC>;
+ theme: DeepPartial;
+ label: string;
+ showLabel: boolean;
+}
+
+const BottomNavItemBtn: FC = (props) => {
+ const { icon: Icon, customClassName = "", reactId, label, showLabel, theme: customTheme = {}, ...rest } = props;
+
+ const theme = mergeDeep(getTheme().bottomNavigation.item, customTheme);
+
+ return (
+
+
+
+ {showLabel ? {label} : null}
+
+ );
+};
+
+export const BottomNavigationItem: FC = ({
+ icon: Icon,
+ label,
+ theme: customTheme = {},
+ showTooltip = false,
+ showLabel = true,
+ className,
+ ...props
+}) => {
+ const id = useId();
+
+ return (
+ <>
+ {showTooltip ? (
+
+ {label}
+
+ }
+ placement="top"
+ >
+
+
+ ) : (
+
+ )}
+ >
+ );
+};
+
+BottomNavigationItem.displayName = "BottomNavigation.Item";
diff --git a/packages/ui/src/components/BottomNavigation/index.ts b/packages/ui/src/components/BottomNavigation/index.ts
new file mode 100644
index 000000000..6c9e2daf0
--- /dev/null
+++ b/packages/ui/src/components/BottomNavigation/index.ts
@@ -0,0 +1,5 @@
+export { BottomNavigation } from "./BottomNavigation";
+export type { FlowbiteBottomNavigationTheme, BottomNavigationProps } from "./BottomNavigation";
+
+export { BottomNavigationItem } from "./BottomNavigationItem";
+export type { BottomNavigationItemProps, FlowbiteBottomNavigationItemTheme } from "./BottomNavigationItem";
diff --git a/packages/ui/src/components/BottomNavigation/theme.ts b/packages/ui/src/components/BottomNavigation/theme.ts
new file mode 100644
index 000000000..136761ab8
--- /dev/null
+++ b/packages/ui/src/components/BottomNavigation/theme.ts
@@ -0,0 +1,19 @@
+import type { FlowbiteBottomNavigationTheme } from "./BottomNavigation";
+
+export const bottomNavigationTheme: FlowbiteBottomNavigationTheme = {
+ root: {
+ base: "fixed bottom-0 left-0 z-50 w-full h-16 bg-white border-t border-gray-200 dark:bg-gray-700 dark:border-gray-600",
+ inner: "grid h-full max-w-lg grid-cols-4 mx-auto font-medium w-fit",
+ },
+ border: {
+ on: "border-gray-200 [&_button]:border",
+ off: "",
+ },
+ item: {
+ base: "inline-flex flex-col items-center justify-center px-5 py-3 hover:bg-gray-50 dark:hover:bg-gray-800 group",
+ icon: {
+ base: "w-5 h-5 mb-2 text-gray-500 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-500",
+ },
+ label: "text-sm text-gray-500 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-500",
+ },
+};
diff --git a/packages/ui/src/components/Flowbite/FlowbiteTheme.ts b/packages/ui/src/components/Flowbite/FlowbiteTheme.ts
index a0ce75db5..0f197643a 100644
--- a/packages/ui/src/components/Flowbite/FlowbiteTheme.ts
+++ b/packages/ui/src/components/Flowbite/FlowbiteTheme.ts
@@ -4,6 +4,7 @@ import type { FlowbiteAlertTheme } from "../Alert";
import type { FlowbiteAvatarTheme } from "../Avatar";
import type { FlowbiteBadgeTheme } from "../Badge";
import type { FlowbiteBlockquoteTheme } from "../Blockquote";
+import type { FlowbiteBottomNavigationTheme } from "../BottomNavigation";
import type { FlowbiteBreadcrumbTheme } from "../Breadcrumb";
import type { FlowbiteButtonGroupTheme, FlowbiteButtonTheme } from "../Button";
import type { FlowbiteCardTheme } from "../Card";
@@ -48,6 +49,7 @@ export interface FlowbiteTheme {
avatar: FlowbiteAvatarTheme;
badge: FlowbiteBadgeTheme;
blockquote: FlowbiteBlockquoteTheme;
+ bottomNavigation: FlowbiteBottomNavigationTheme;
breadcrumb: FlowbiteBreadcrumbTheme;
button: FlowbiteButtonTheme;
buttonGroup: FlowbiteButtonGroupTheme;
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index d4ac43525..73cb39798 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -5,6 +5,7 @@ export * from "./components/Avatar";
export * from "./components/Badge";
export * from "./components/Banner";
export * from "./components/Blockquote";
+export * from "./components/BottomNavigation";
export * from "./components/Breadcrumb";
export * from "./components/Button";
export * from "./components/Card";
diff --git a/packages/ui/src/theme.ts b/packages/ui/src/theme.ts
index a5c64cb0b..3fa0b8251 100644
--- a/packages/ui/src/theme.ts
+++ b/packages/ui/src/theme.ts
@@ -4,6 +4,7 @@ import { alertTheme } from "./components/Alert/theme";
import { avatarTheme } from "./components/Avatar/theme";
import { badgeTheme } from "./components/Badge/theme";
import { blockquoteTheme } from "./components/Blockquote/theme";
+import { bottomNavigationTheme } from "./components/BottomNavigation/theme";
import { breadcrumbTheme } from "./components/Breadcrumb/theme";
import { buttonGroupTheme, buttonTheme } from "./components/Button/theme";
import { cardTheme } from "./components/Card/theme";
@@ -46,6 +47,7 @@ export const theme: FlowbiteTheme = {
avatar: avatarTheme,
badge: badgeTheme,
blockquote: blockquoteTheme,
+ bottomNavigation: bottomNavigationTheme,
breadcrumb: breadcrumbTheme,
button: buttonTheme,
buttonGroup: buttonGroupTheme,