A popup component that displays informative text when users hover over, focus on, or click an element.
dialog
- Copy Demo
TOP
LEFT
RIGHT
BOTTOM
Link to Rust/UI
use icons::{ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Link};
use leptos::prelude::*;
use crate::components::ui::button::{Button, ButtonVariant};
use crate::components::ui::tooltip::{Tooltip, TooltipContent, TooltipPosition, TooltipProvider};
#[component]
pub fn DemoTooltip() -> impl IntoView {
view! {
<TooltipProvider />
<div class="flex flex-col gap-4">
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowUp />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Top.to_string()>"TOP"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowLeft />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Left.to_string()>"LEFT"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowRight />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Right.to_string()>"RIGHT"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowDown />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Bottom.to_string()>"BOTTOM"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary attr:href="https://rust-ui.com">
<Link />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Right.to_string()>"Link to Rust/UI"</TooltipContent>
</Tooltip>
</div>
}
}
Installation
You can run either of the following commands:
# cargo install ui-cli --forceui add demo_tooltipui add tooltip
Update the imports to match your project setup.
Copy and paste the following code into your project:
components/ui/tooltip.rs
use leptos::prelude::*;
use leptos_ui::clx;
use tw_merge::tw_merge;
clx! {Tooltip, div, "inline-block relative mx-0 whitespace-nowrap transition-all duration-300 ease-in-out group/tooltip my-[5px]"}
#[derive(Default, strum::Display)]
pub enum TooltipPosition {
#[default]
Top,
Left,
Right,
Bottom,
}
#[component]
pub fn TooltipContent(
#[prop(into, optional)] class: String,
#[prop(default = TooltipPosition::default())] data_position: TooltipPosition,
children: Children,
) -> impl IntoView {
const SHARED_TRANSITION_CLASSES: &str = "absolute opacity-0 transition-all duration-300 ease-in-out pointer-events-none group-hover/tooltip:opacity-100 z-[1000000]";
let tooltip_class = tw_merge!(
SHARED_TRANSITION_CLASSES,
"py-2 px-2.5 text-xs whitespace-nowrap shadow-lg text-background bg-foreground/90",
class,
match data_position {
TooltipPosition::Top => "left-1/2 bottom-full mb-1 -ml-2.5",
TooltipPosition::Right => "bottom-1/2 left-full ml-2.5 -mb-3.5",
TooltipPosition::Bottom => "left-1/2 top-full mt-1 -ml-2.5",
TooltipPosition::Left => "bottom-1/2 right-full mr-2.5 -mb-3.5",
},
);
let arrow_class = tw_merge!(
"absolute opacity-0 transition-all duration-300 ease-in-out pointer-events-none group-hover/tooltip:opacity-100 z-[1000000]",
"bg-transparent border-transparent border-6",
match data_position {
TooltipPosition::Top => "left-1/2 bottom-full -mb-2 border-t-foreground/90",
TooltipPosition::Right => "bottom-1/2 left-full -mr-0.5 -mb-1 border-r-foreground/90",
TooltipPosition::Bottom => "left-1/2 top-full -mt-2 border-b-foreground/90",
TooltipPosition::Left => "bottom-1/2 right-full -mb-1 -ml-0.5 border-l-foreground/90",
},
);
view! {
<>
<div data-name="TooltipArrow" class=arrow_class />
<div data-name="TooltipContent" class=tooltip_class>
{children()}
</div>
</>
}
}
#[component]
pub fn TooltipProvider() -> impl IntoView {
view! {
<style>
{"
/* JS adds this class to enable interaction */
[data-name=\"TooltipContent\"].tooltip__interactive,
[data-name=\"TooltipContent\"]:hover {
pointer-events: auto;
}
"}
</style>
<div data-name="__TooltipProvider" />
<script>
{"
// Simplified JS - only handles pointer-events for text selection
const tooltipTriggers = document.querySelectorAll('[data-name=\"Tooltip\"]');
tooltipTriggers.forEach(trigger => {
const content = trigger.querySelector('[data-name=\"TooltipContent\"]');
trigger.addEventListener('mouseenter', () => {
content.classList.add('tooltip__interactive');
});
trigger.addEventListener('mouseleave', () => {
setTimeout(() => {
content.classList.remove('tooltip__interactive');
}, 100);
});
});
"}
</script>
}
}
Update the imports to match your project setup.
Usage
use crate::registry::ui::tooltip::{Tooltip, TooltipContent, TooltipPosition, TooltipProvider};
<TooltipProvider />
<Tooltip>
<Button>"Hover me"</Button>
<TooltipContent>"This is a tooltip"</TooltipContent>
</Tooltip>
Examples
Positions
The tooltip can be positioned in different directions using the TooltipPosition
enum.
- Copy Demo
TOP
LEFT
RIGHT
BOTTOM
Link to Rust/UI
use icons::{ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Link};
use leptos::prelude::*;
use crate::components::ui::button::{Button, ButtonVariant};
use crate::components::ui::tooltip::{Tooltip, TooltipContent, TooltipPosition, TooltipProvider};
#[component]
pub fn DemoTooltip() -> impl IntoView {
view! {
<TooltipProvider />
<div class="flex flex-col gap-4">
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowUp />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Top.to_string()>"TOP"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowLeft />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Left.to_string()>"LEFT"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowRight />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Right.to_string()>"RIGHT"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary>
<ArrowDown />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Bottom.to_string()>"BOTTOM"</TooltipContent>
</Tooltip>
<Tooltip>
<Button variant=ButtonVariant::Secondary attr:href="https://rust-ui.com">
<Link />
</Button>
<TooltipContent attr:data-position=TooltipPosition::Right.to_string()>"Link to Rust/UI"</TooltipContent>
</Tooltip>
</div>
}
}
Components
The tooltip system consists of three main components:
TooltipProvider
: Provides the JavaScript functionality for interactive tooltipsTooltip
: The wrapper component that contains both trigger and contentTooltipContent
: The actual tooltip content with positioning
API
TooltipPosition
pub enum TooltipPosition {
Top,
Left,
Right,
Bottom,
}