MC Hover Card

A card that appears on hover with additional information.

Overview

The mc-hover-card is a lightweight, hover-triggered card component in the MicroClub UI library. Built on the @base-ui/react preview-card primitive, it delivers accessible hover interactions with a flexible card layout and image/content support.

This component is designed for seamless integration into your codebase, with customizable alignment, offset, and content props.

Preview

import { McHoverCard, McHoverCardContent, McHoverCardTrigger } from '../ui/mc-hover-card';export default function McHoverCardDemo() {  return (    <div>      <McHoverCard>        <McHoverCardTrigger>          <button type="button" className="cursor-pointer rounded-full">            hover me          </button>        </McHoverCardTrigger>        <McHoverCardContent          textAlign="start"          title="John Doe"          subtitle="Software Engineer"          description="John is a software engineer with 5 years of experience in web development. He loves working with React and TypeScript."        />      </McHoverCard>    </div>  );}

Add to Your Project

Deploy the mc-hover-card directly to your components/ui directory:

npx mcoli-ui@latest add mc-hover-card
pnpm dlx mcoli-ui@latest add mc-hover-card
yarn dlx mcoli-ui@latest add mc-hover-card
bunx mcoli-ui@latest add mc-hover-card

Manual Setup

If you prefer manual control:

Install the core dependencies
npm install @base-ui/react
pnpm add @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react
Copy the source code
'use client';import { PreviewCard as PreviewCardPrimitive } from '@base-ui/react/preview-card';import { cn } from '@/lib/utils';function McHoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {  return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />;}function McHoverCardTrigger({ ...props }: PreviewCardPrimitive.Trigger.Props) {  return <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />;}function McHoverCardContent({  className,  side = 'bottom',  sideOffset = 4,  align = 'center',  alignOffset = 4,  textAlign = 'start',  imageSrc = null,  imageposition = 'top',  title,  subtitle,  description,  ...props}: PreviewCardPrimitive.Popup.Props &  Pick<PreviewCardPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'> & {    textAlign?: 'start' | 'center';    imageSrc?: string | null;    imageposition?: 'top' | 'bottom';    title?: string;    subtitle?: string;    description?: string;  }) {  return (    <PreviewCardPrimitive.Portal data-slot="hover-card-portal">      <PreviewCardPrimitive.Positioner        align={align}        alignOffset={alignOffset}        side={side}        sideOffset={sideOffset}        className="isolate z-50 w-76 origin-(--transform-origin) rounded-lg bg-card p-4 text-sm text-popover-foreground shadow-md ring-inset  ring-1 ring-border flex flex-col "      >        <div className={`${imageposition === 'top' ? 'flex-col' : 'flex-col-reverse'} flex gap-4`}>          {imageSrc && <img src={imageSrc} alt="Profile" className={`w-full    `} />}          <div            className={`${textAlign === 'start' ? 'items-start' : 'items-center'} flex flex-col gap-2`}          >            {title && <h4 className="font-semibold text-card-foreground">{title}</h4>}            <div              className={`${textAlign === 'start' ? 'items-start' : 'text-center'} flex flex-col`}            >              {subtitle && <p className=" font-regular text-card-foreground">{subtitle}</p>}              {description && <p className="font-regular text-card-foreground">{description}</p>}            </div>          </div>        </div>        <PreviewCardPrimitive.Popup          data-slot="hover-card-content"          className={cn(            ' outline-hidden duration-100   ',            ' data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 ',            ' data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ',            ' data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 ',            'data-closed:zoom-out-95 gap-4',            className          )}          {...props}        />      </PreviewCardPrimitive.Positioner>    </PreviewCardPrimitive.Portal>  );}export { McHoverCard, McHoverCardTrigger, McHoverCardContent };
Adjust import paths

Ensure your @/lib/utils or equivalent classname helper is correctly imported.

Usage

import { McHoverCard, McHoverCardTrigger, McHoverCardContent } from '@/components/ui/mc-hover-card';

export default function Example() {
  return (
    <McHoverCard>
      <McHoverCardTrigger>
        <button type="button">Hover me</button>
      </McHoverCardTrigger>
      <McHoverCardContent
        title="John Doe"
        subtitle="Software Engineer"
        description="John is a software engineer with 5 years of experience in web development. He loves working with React and TypeScript."
        imageSrc="https://cdn-imgix.headout.com/media/images/c9db3cea62133b6a6bb70597326b4a34-388-dubai-img-worlds-of-adventure-tickets-01.jpg?auto=compress%2Cformat&w=1222.3999999999999&h=687.6&q=90&ar=16%3A9&crop=faces&fit=crop"
      />
    </McHoverCard>
  );
}

Examples

Image Top

<McHoverCard>
  <McHoverCardTrigger>
    <button type="button">Hover me</button>
  </McHoverCardTrigger>
  <McHoverCardContent
    textAlign="start"
    imageSrc="https://cdn-imgix.headout.com/media/images/c9db3cea62133b6a6bb70597326b4a34-388-dubai-img-worlds-of-adventure-tickets-01.jpg?auto=compress%2Cformat&w=1222.3999999999999&h=687.6&q=90&ar=16%3A9&crop=faces&fit=crop"
    title="John Doe"
    subtitle="Software Engineer"
    description="John is a software engineer with 5 years of experience in web development. He loves working with React and TypeScript."
  />
</McHoverCard>

Bottom Image

<McHoverCard>
  <McHoverCardTrigger>
    <button type="button">Hover me</button>
  </McHoverCardTrigger>
  <McHoverCardContent
    imageposition="bottom"
    textAlign="center"
    title="Profile"
    subtitle="Designer"
    description="A bold hover card with the image placed below the content and centered text alignment."
  />
</McHoverCard>

Side Placement

<McHoverCard>
  <McHoverCardTrigger>
    <button type="button">Hover me</button>
  </McHoverCardTrigger>
  <McHoverCardContent side="right" sideOffset={8} align="start" alignOffset={8}>
    <div className="space-y-2">
      <h4 className="font-semibold">Details</h4>
      <p className="text-sm">
        Use `side`, `sideOffset`, `align`, and `alignOffset` to control the hover card position.
      </p>
    </div>
  </McHoverCardContent>
</McHoverCard>

API Reference

Props

PropTypeDefaultDescription
titlestringundefinedMain heading displayed inside the hover card
subtitlestringundefinedSecondary line of text below the title
descriptionstringundefinedBody text shown inside the card
imageSrcstring | nullnullOptional image URL shown above or below the content
imageposition"top" | "bottom""top"Position of the image relative to the text content
textAlign"start" | "center""start"Text alignment for title, subtitle, and description
side"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end""bottom"Side where the hover card appears
sideOffsetnumber4Offset distance from the trigger on the specified side
align"start" | "center" | "end""center"Alignment of the hover card relative to the trigger
alignOffsetnumber4Offset distance along the alignment axis
classNamestringundefinedAdditional CSS classes passed to the hover card content

All other props from @base-ui/react/preview-card are supported.

On this page