FloatingMessage
Display a temporary floating feedback Message
import FloatingMessage from "@intility/bifrost-react/FloatingMessage";A floating message is suitable only for temporary low-priority feedback.
- Pops up in
bottom rightcorner (configurable) - Disappears after
7seconds (configurable) - Displays up to
3stacked messages (configurable) - Stays visible as long as mouse cursor is hovering over the message
- Read aloud by screen readers when opened
Setup
Wrap your app content in the <FloatingMessage> provider, then use
useFloatingMessage() hook to access the
showFloatingMessage(message, options) method.
Only use a single <FloatingMessage> in your app (to avoid any message
overlap). The useFloatingMessage hook will then be available to use in any
descendant component.
Ideally place it inside <Nav> to avoid overlapping with the
menus, but if you need to show messages from code residing in the menu (or
outside) you will need to move the provider higher in the hierarchy. If you
place messages top and/or left you then need to manually prevent overlapping
with the menu with some custom CSS.
A typical setup might look something like this:
import Nav from "@intility/bifrost-react/Nav"; import FloatingMessage from "@intility/bifrost-react/FloatingMessage"; import useFloatingMessage from "@intility/bifrost-react/hooks/useFloatingMessage"; function MyComponent() { const { showFloatingMessage } = useFloatingMessage(); // probably inside a click handler or other event showFloatingMessage("Hello world"); } // in your main / layout file <Nav> <FloatingMessage> Rest of your app here <MyComponent /> </FloatingMessage> </Nav>;
The showFloatingMessage(message, options)method accepts two parameters:
messagesimple string or tsxoptionsoptional object, forwarded as props for<Message>
Demo
const { showFloatingMessage } = useFloatingMessage(); // Show message showFloatingMessage("Message text"); // Without icon showFloatingMessage("Message text", { state: "success", noIcon: true, }); // Formatted alert showFloatingMessage( <> Message text <em>with formatting</em> </>, { state: "alert" }, );
Timeout, max messages and position
A message will be shown for 7000ms (seven seconds) by default, but can be
configured through the timeout prop. Set to 0 for no timeout.
Up to 3 messages are displayed at a time by default, but can be configured
through the max prop.
Default positioning is bottom right corner, but can be placed top and/or
left as well.
<FloatingMessage timeout={10000} max={1} top left> [app content] </FloatingMessage>
Custom close button
We expose a removeFloatingMessage() method, but it will only be available for
components rendered inside of a floating message, so you'll need to create a
separate component and call the useFloatingMessage() hook from there:
function RemoveButton() { // removeFloatingMessage will only exist when nested inside a floating message const { removeFloatingMessage } = useFloatingMessage(); return <Button onClick={() => removeFloatingMessage?.()}>I got it</Button>; }
Then you can pass your content including your RemoveButton component as JSX to
the first parameter of showFloatingMessage().
showFloatingMessage( <> Message text <RemoveButton /> </>, );
Optionally disable the default
x close button by passing undefined to the onClose option object (second
parameter).
showFloatingMessage( <> Disable default onClose <RemoveButton /> </>, { onClose: undefined }, );
Sandbox
import Button from "@intility/bifrost-react/Button"; import FloatingMessage from "@intility/bifrost-react/FloatingMessage"; import useFloatingMessage from "@intility/bifrost-react/hooks/useFloatingMessage"; export default function FloatingMessageDemo() { return ( <FloatingMessage> <MyComponent /> </FloatingMessage> ); } function MyComponent() { const { showFloatingMessage } = useFloatingMessage(); return ( <div className="bfl-inline"> <Button onClick={() => showFloatingMessage(randomMessage())}> Show message </Button> <Button onClick={() => showFloatingMessage(randomMessage(), { state: "success", noIcon: true, }) } > Without icon </Button> <Button onClick={() => showFloatingMessage( <> {randomMessage()} <em>with formatting</em> </>, { state: "alert", }, ) } > Formatted alert </Button> </div> ); } const messages = [ "He's a friend from work!", "Are you Thor, The God of Hammers?", "Oh my god, the hammer pulled you off?", "Is he though?", "We're not doing 'Get Help'", "Yeah, same. Hulk like fire, Thor like water.", "Asgard is not a place, it's a people.", "Piss off, ghost!", "I have been falling, for thirty minutes!", "We need one with cupholders.", "Yes! That's how that feels!", ]; function randomMessage() { return messages[Math.round(Math.random() * (messages.length - 1))]; }
Avoid overlapping
Floating/fixed elements at the bottom of the screen might overlap with a
floating message, like the <BottomBar> component. You can place messages at
top of the screen instead, or add some bottom space with some custom CSS that
is only rendered when the BottomBar is.
import { useState } from "react"; import { faHome, faUser, faCog } from "@fortawesome/free-solid-svg-icons"; import FloatingMessage from "@intility/bifrost-react/FloatingMessage"; import useFloatingMessage from "@intility/bifrost-react/hooks/useFloatingMessage"; import Button from "@intility/bifrost-react/Button"; import BottomBar from "@intility/bifrost-react/BottomBar"; import Nav from "@intility/bifrost-react/Nav"; export default function () { const [page, setPage] = useState(10); return ( <div className="page-demo" // simulate no sidebar for demo only style={{ "--bf-nav-side-width": "0px", minHeight: 300 }} > <FloatingMessage> <MyComponent /> </FloatingMessage> </div> ); } const MyComponent = () => { const { showFloatingMessage } = useFloatingMessage(); const [displayBottomBar, setDisplayBottomBar] = useState(true); return ( <> <div className="bfl-inline"> <Button onClick={() => showFloatingMessage(randomMessage())}> Show message </Button> <Button onClick={() => setDisplayBottomBar(!displayBottomBar)}> Toggle bottom bar </Button> </div> {displayBottomBar && ( // only render style tag when bottombar is rendered <> <style>{` .page-demo .bf-floatingmessage-stack { bottom: 40px } `}</style> <BottomBar>Some bottom bar content</BottomBar> </> )} </> ); }; const messages = [ "He's a friend from work!", "Are you Thor, The God of Hammers?", "Oh my god, the hammer pulled you off?", "Is he though?", "We're not doing 'Get Help'", "Yeah, same. Hulk like fire, Thor like water.", "Asgard is not a place, it's a people.", "Piss off, ghost!", "I have been falling, for thirty minutes!", "We need one with cupholders.", "Yes! That's how that feels!", ]; function randomMessage() { return messages[Math.round(Math.random() * (messages.length - 1))]; }