Hover Card

For sighted users to preview content available behind a link.

Requires JavaScript
hover-card/default
<%= render Shadcn::HoverCardComponent.new do |card| %>
  <% card.with_trigger do %>
    <span class="underline cursor-pointer">Hover over me</span>
  <% end %>
  <% card.with_card_content do %>
    <p class="text-sm">This is the hover card content.</p>
  <% end %>
<% end %>

Installation

Add the component to your project:

rails generate shadcn:add hover_card

Usage

<%= render Shadcn::HoverCardComponent.new do |card| %>
  <% card.with_trigger do %>
    <span class="underline cursor-pointer">Hover over me</span>
  <% end %>
  <% card.with_card_content do %>
    <p class="text-sm">This is the hover card content.</p>
  <% end %>
<% end %>

Examples

Basic

A simple hover card with text content.

Hover over me
<%= render Shadcn::HoverCardComponent.new do |card| %>
  <% card.with_trigger do %>
    <span class="underline cursor-pointer">Hover over me</span>
  <% end %>
  <% card.with_card_content do %>
    <p class="text-sm">This is the hover card content.</p>
  <% end %>
<% end %>

User Profile Preview

Display user information on hover, commonly used for social media style mentions.

<%= render Shadcn::HoverCardComponent.new do |card| %>
  <% card.with_trigger do %>
    <a href="#" class="underline">@nextjs</a>
  <% end %>
  <% card.with_card_content do %>
    <div class="flex justify-between space-x-4">
      <%= render Shadcn::AvatarComponent.new(src: "https://github.com/vercel.png", alt: "@nextjs", fallback: "VR") %>
      <div class="space-y-1">
        <h4 class="text-sm font-semibold">@nextjs</h4>
        <p class="text-sm">The React Framework - created and maintained by @vercel.</p>
        <div class="flex items-center pt-2">
          <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1 opacity-70" viewBox="0 0 20 20" fill="currentColor">
            <path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
          </svg>
          <span class="text-xs text-muted-foreground">Joined December 2021</span>
        </div>
      </div>
    </div>
  <% end %>
<% end %>

Link Preview

Show a preview of external links on hover.

<%= render Shadcn::HoverCardComponent.new do |card| %>
  <% card.with_trigger do %>
    <a href="https://github.com/rails/rails" class="text-primary hover:underline">
      Ruby on Rails
    </a>
  <% end %>
  <% card.with_card_content do %>
    <div class="space-y-2">
      <h4 class="text-sm font-semibold">Ruby on Rails</h4>
      <p class="text-sm text-muted-foreground">
        A web-application framework that includes everything needed to create
        database-backed web applications according to the Model-View-Controller (MVC) pattern.
      </p>
      <div class="flex items-center pt-2">
        <span class="text-xs text-muted-foreground">github.com/rails/rails</span>
      </div>
    </div>
  <% end %>
<% end %>

Custom Delays

Customize the delay before the card opens and closes. Useful for adjusting the hover sensitivity.

Quick hover (200ms open, 100ms close)
<%= render Shadcn::HoverCardComponent.new(open_delay: 200, close_delay: 100) do |card| %>
  <% card.with_trigger do %>
    <span class="underline cursor-pointer">Quick hover (200ms open, 100ms close)</span>
  <% end %>
  <% card.with_card_content do %>
    <p class="text-sm">This card appears faster and closes quicker.</p>
  <% end %>
<% end %>

Positioning

Control where the hover card appears relative to the trigger using the side and align options.

<div class="flex gap-4 flex-wrap">
  <%= render Shadcn::HoverCardComponent.new do |card| %>
    <% card.with_trigger do %>
      <%= render Shadcn::ButtonComponent.new(variant: :outline) { "Top" } %>
    <% end %>
    <% card.with_card_content(side: :top) do %>
      <p class="text-sm">Appears on top</p>
    <% end %>
  <% end %>

  <%= render Shadcn::HoverCardComponent.new do |card| %>
    <% card.with_trigger do %>
      <%= render Shadcn::ButtonComponent.new(variant: :outline) { "Right" } %>
    <% end %>
    <% card.with_card_content(side: :right) do %>
      <p class="text-sm">Appears on right</p>
    <% end %>
  <% end %>

  <%= render Shadcn::HoverCardComponent.new do |card| %>
    <% card.with_trigger do %>
      <%= render Shadcn::ButtonComponent.new(variant: :outline) { "Bottom" } %>
    <% end %>
    <% card.with_card_content(side: :bottom) do %>
      <p class="text-sm">Appears on bottom</p>
    <% end %>
  <% end %>

  <%= render Shadcn::HoverCardComponent.new do |card| %>
    <% card.with_trigger do %>
      <%= render Shadcn::ButtonComponent.new(variant: :outline) { "Left" } %>
    <% end %>
    <% card.with_card_content(side: :left) do %>
      <p class="text-sm">Appears on left</p>
    <% end %>
  <% end %>
</div>

Top Position

hover-card/top
<%= render Shadcn::HoverCard.new do |card| %>
  <% card.with_trigger do %>
    <%= render Shadcn::Button.new(variant: :outline) { "Top" } %>
  <% end %>
  <% card.with_card_content(side: :top) do %>
    <p class="text-sm">Appears on top</p>
  <% end %>
<% end %>

Custom Delay

hover-card/custom_delay
<%= render Shadcn::HoverCard.new(open_delay: 200, close_delay: 100) do |card| %>
  <% card.with_trigger do %>
    <span class="underline cursor-pointer">Quick hover (200ms open, 100ms close)</span>
  <% end %>
  <% card.with_card_content do %>
    <p class="text-sm">This card appears faster and closes quicker.</p>
  <% end %>
<% end %>

With Avatar

JD
hover-card/with_avatar
<%= render Shadcn::HoverCard.new do |card| %>
  <% card.with_trigger do %>
    <a href="#" class="underline">@nextjs</a>
  <% end %>
  <% card.with_card_content do %>
    <div class="flex justify-between space-x-4">
      <%= render Shadcn::Avatar.new(src: "https://github.com/vercel.png", alt: "@nextjs", fallback: "VR") %>
      <div class="space-y-1">
        <h4 class="text-sm font-semibold">@nextjs</h4>
        <p class="text-sm">The React Framework - created and maintained by @vercel.</p>
        <div class="flex items-center pt-2">
          <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1 opacity-70" viewBox="0 0 20 20" fill="currentColor">
            <path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
          </svg>
          <span class="text-xs text-muted-foreground">Joined December 2021</span>
        </div>
      </div>
    </div>
  <% end %>
<% end %>

API Reference

HoverCardComponent

Prop Type Default Description
open_delay Integer 700 Delay in milliseconds before the card opens on hover
close_delay Integer 300 Delay in milliseconds before the card closes after mouse leaves

Slots

Slot Props Description
with_trigger - The element that triggers the hover card (link, button, etc.)
with_card_content side:, align: The content to display in the hover card

HoverCardContentComponent

Prop Type Default Description
side Symbol :bottom Position of the card relative to trigger: :top, :right, :bottom, :left
align Symbol :center Alignment of the card: :start, :center, :end

Stimulus Controller

This component requires JavaScript. The Stimulus controller shadcn--hover-card provides interactivity.

Manages hover card visibility with configurable delays for opening and closing. Handles mouse and keyboard events for accessibility.

Installation

Add to your config/importmap.rb:

pin "shadcn", to: "index.esm.js"

Then in your app/javascript/controllers/index.js:

import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn"

const application = Application.start()
registerShadcnControllers(application)

Or import just this controller:

import HoverCardController from "shadcn-rails-stimulus/controllers/hover_card_controller"

application.register("shadcn--hover-card", HoverCardController)

Targets

Name Description
trigger The element that triggers the hover card to appear
content The hover card content container

Values

Name Type Default Description
openDelay Number 700 Delay in milliseconds before opening
closeDelay Number 300 Delay in milliseconds before closing

Actions

Action Description
open Opens the hover card immediately
close Closes the hover card immediately
scheduleOpen Schedules the card to open after openDelay
scheduleClose Schedules the card to close after closeDelay

TypeScript

Type definitions are included. Import types as needed:

import type { HoverCardController } from "shadcn-rails-stimulus"

Accessibility

  • Uses role="tooltip" for proper screen reader announcement
  • Responds to both mouse hover and keyboard focus events
  • Content appears on hover and focus, disappears on blur and mouse leave
  • Configurable delays prevent accidental triggers from brief mouse movements
  • Mouse can move over the card content without it closing
  • For sighted users only - does not provide accessible alternative for screen reader users
  • Consider providing the same information through other means for non-sighted users