Demo

Adding Floating action button

Add a mobile-only primary action with FloatingActionButton, FloatingButton, and FloatingContainer from @quan-erp/shared-ui. Gate with isMobile and shift when the bottom nav is visible.

Goal

Give mobile list pages a clear primary action (create, quick add, multi-action expand) without crowding the header — while desktop keeps actions in PageTitle / toolbars.

  • FAB is mobile-only — hide on desktop
  • Import FloatingActionButton, FloatingButton, FloatingContainer from @quan-erp/shared-ui
  • Shift with useIsContainInBottomNavBar — bottom-25 vs bottom-5
  • Pair with responsive card lists, not dense tables alone

1. Prerequisites

You need a page that already branches on isMobile (or will) and knows its route path for bottom-nav checks.

  • @quan-erp/shared-ui and @quan-erp/base-frontend installed on the plugin frontend
  • Page path under /${metadata.name}/… registered via AppRegistry.route.add()
  • Mobile layout in place (cards) so the FAB has a list to act on

2. Gate with isMobile + bottom nav

Always compute isMobile and whether this path appears in the bottom nav before rendering the FAB.

  • isMobile — hide FAB entirely on desktop
  • isContainInBottomNav — true when this path is listed in bottom nav
  • className — absolute + bottom-25 (nav visible) or bottom-5 (hidden)
  • adaptivePosition={true} — recommended so the FAB stays clear of safe areas
TSXhooks
1import { 2 FloatingActionButton, 3 FloatingButton, 4 FloatingContainer, 5 Button, 6 SCREENS, 7 useMediaQuery, 8 cn, 9} from "@quan-erp/shared-ui"; 10import { useIsContainInBottomNavBar } from "@quan-erp/base-frontend"; 11import { Plus } from "@icon-park/react"; 12import metadata from "../../module.metadata.json" with { type: "json" }; 13 14const isMobile = useMediaQuery(SCREENS.md); 15const isContainInBottomNav = useIsContainInBottomNavBar( 16 `/${metadata.name}/my-page`, 17);

3. Single button

One primary action (usually create). Set expandable={false} and wrap a Button inside FloatingButton.

  • Render only inside {isMobile && (…)}
  • onClick opens the same create dialog / sheet used on desktop PageTitle
  • Icon-only Button with size="icon-lg" matches shared-ui patterns
JSONsingle FAB
1{isMobile && ( 2 <FloatingActionButton 3 className={cn( 4 "absolute", 5 isContainInBottomNav ? "bottom-25" : "bottom-5", 6 )} 7 adaptivePosition={true} 8 expandable={false} 9 > 10 <FloatingButton> 11 <Button size="icon-lg" onClick={() => handleCreate()}> 12 <Plus /> 13 </Button> 14 </FloatingButton> 15 </FloatingActionButton> 16)}

4. Expandable multi-button

When several related actions share one FAB, set rowSpan and expandClassName, put the trigger in FloatingButton, and actions in FloatingContainer.

  • rowSpan — number of action rows in the expanded panel
  • expandClassName — width of the expanded container
  • Keep labels short; each Button should call the same handlers as desktop menus
JSONexpandable
1{isMobile && ( 2 <FloatingActionButton 3 rowSpan={2} 4 expandClassName="w-[15rem]" 5 adaptivePosition={true} 6 className={cn( 7 "absolute", 8 isContainInBottomNav ? "bottom-25" : "bottom-5", 9 )} 10 > 11 <FloatingButton> 12 <Plus /> 13 </FloatingButton> 14 <FloatingContainer> 15 <Button className="w-full h-full" onClick={() => actionOne()}> 16 Action One 17 </Button> 18 <Button className="w-full h-full" onClick={() => actionTwo()}> 19 Action Two 20 </Button> 21 </FloatingContainer> 22 </FloatingActionButton> 23)}

5. Verify

Check mobile and desktop, with and without bottom nav membership.

  • Desktop — FAB not visible; PageTitle / toolbar still has create
  • Mobile, path not in bottom nav — FAB at bottom-5, tap opens create
  • Mobile, path in bottom nav — FAB at bottom-25, clears the bar
  • Expandable — tap expands; both actions fire correctly
  • Rotate / resize across SCREENS.md — FAB appears/disappears with isMobile

Common mistakes

  • Showing FAB on desktop — duplicates PageTitle actions and looks wrong
  • Hardcoding bottom-5 always — FAB sits under the bottom nav
  • Wrong path in useIsContainInBottomNavBar — position never shifts
  • FAB without a mobile card list — floating create over an unusable dense table
  • Different create handlers on FAB vs desktop — behavior drifts