Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions tooltip-hover-card/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# TooltipHoverCard

A versatile tooltip and hover card component that displays contextual information when hovering over or focusing on a trigger element.

## Getting Started

Install dependencies:
```bash
npm install
```

Share the component to your Webflow workspace:
```bash
npx webflow library share
```

For local development:
```bash
npm run dev
```

## Designer Properties

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| ID | Id | — | HTML ID attribute for targeting and accessibility |
| Mode | Variant | tooltip | Display mode: simple text tooltip or rich hover card |
| Theme | Variant | dark | Visual theme for the tooltip/card background and text |
| Placement | Variant | top | Preferred placement relative to trigger element |
| Trigger Text | TextNode | Hover me | Text content of the trigger element |
| Tooltip Text | Text | This is helpful information | Plain text content for tooltip mode |
| Card Title | Text | More Information | Title text for hover card mode |
| Card Description | RichText | This hover card provides detailed contextual information with formatting support for better readability. | Rich text description content for hover card mode |
| Card Image | Image | — | Optional image displayed in hover card mode |
| Show Card Image | Visibility | — | Show or hide the image in hover card mode |
| Hover Delay | Number | 200 | Delay in milliseconds before tooltip appears on hover |
| Show Arrow | Boolean | true | Display arrow pointer to trigger element |
| Auto Flip | Boolean | true | Automatically flip placement when near viewport edges |
| Max Width | Number | 300 | Maximum width of tooltip/card in pixels |
| Aria Label | Text | Additional information | Accessible label for screen readers |

## Styling

This component automatically adapts to your Webflow site's design system through site variables and inherited properties.

### Site Variables

To match your site's design system, define these CSS variables in your Webflow project settings. The component will use the fallback values shown below until you configure them.

| Site Variable | What It Controls | Fallback |
|---------------|------------------|----------|
| --background-primary | Light theme background color | #ffffff |
| --background-secondary | Hover state background color | #f5f5f5 |
| --text-primary | Light theme text color | #1a1a1a |
| --text-secondary | Secondary text elements and borders on hover | #737373 |
| --border-color | Border and divider colors | #e5e5e5 |
| --accent-color | Dark theme background and focus outline color | #1a1a1a |
| --accent-text-color | Dark theme text color | #ffffff |
| --border-radius | Corner rounding for all elements | 8px |

### Inherited Properties

The component inherits these CSS properties from its parent element:
- `font-family` — Typography style
- `color` — Text color
- `line-height` — Text spacing

## Extending in Code

### Custom Tooltip Positioning Logic

You can extend the component's positioning behavior by accessing the tooltip element and implementing custom placement calculations:

```javascript
const tooltip = document.querySelector('[data-tooltip-id="my-tooltip"]');
// Add custom viewport boundary detection
// Implement custom offset calculations based on trigger position
```

### Dynamic Content Updates

Update tooltip or hover card content dynamically based on user interactions or data changes:

```javascript
const tooltipComponent = document.querySelector('#my-tooltip');
// Update tooltip text based on context
// Swap between tooltip and hover card modes programmatically
// Adjust hover delay based on user preferences
```

## Dependencies

No external dependencies.
17 changes: 17 additions & 0 deletions tooltip-hover-card/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TooltipHoverCard</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; }
body { color: inherit; }
h1, h2, h3, h4, h5, h6 { color: inherit; }
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
5 changes: 5 additions & 0 deletions tooltip-hover-card/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Tooltip & Hover Card",
"description": "Contextual popover with placement options and arrow indicator",
"category": "Overlay"
}
25 changes: 25 additions & 0 deletions tooltip-hover-card/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "tooltip-hover-card",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
"devDependencies": {
"@types/react": "^19.1.13",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^5.0.3",
"@webflow/data-types": "^1.0.1",
"@webflow/react": "^1.0.1",
"@webflow/webflow-cli": "^1.8.44",
"typescript": "~5.8.3",
"vite": "^7.1.7"
}
}
1 change: 1 addition & 0 deletions tooltip-hover-card/screenshot-brand.b64

Large diffs are not rendered by default.

Binary file added tooltip-hover-card/screenshot-brand.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tooltip-hover-card/screenshot-dark.b64

Large diffs are not rendered by default.

Binary file added tooltip-hover-card/screenshot-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tooltip-hover-card/screenshot-light.b64

Large diffs are not rendered by default.

Binary file added tooltip-hover-card/screenshot-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
/*
* Webflow Site Variables Used:
* - --background-primary: Light theme background
* - --background-secondary: Hover states
* - --text-primary: Light theme text
* - --text-secondary: Secondary text elements
* - --border-color: Borders and dividers
* - --accent-color: Dark theme background
* - --accent-text-color: Dark theme text
* - --border-radius: Corner rounding
*/

/* Box sizing reset */
.wf-tooltiphovercard *,
.wf-tooltiphovercard *::before,
.wf-tooltiphovercard *::after {
box-sizing: border-box;
}

/* Root element - inherit Webflow typography + default padding */
.wf-tooltiphovercard {
font-family: inherit;
color: inherit;
line-height: inherit;
padding: 24px;
display: inline-block;
--wf-tooltiphovercard-max-width: 300px;
}

/* Trigger button */
.wf-tooltiphovercard-trigger {
background: transparent;
border: 1px solid var(--border-color, #e5e5e5);
padding: 8px 16px;
cursor: pointer;
border-radius: var(--border-radius, 8px);
color: var(--text-primary, #1a1a1a);
font-size: 14px;
font-family: inherit;
line-height: inherit;
transition: background-color 0.2s, border-color 0.2s;
}

.wf-tooltiphovercard-trigger:hover {
background: var(--background-secondary, #f5f5f5);
border-color: var(--text-secondary, #737373);
}

.wf-tooltiphovercard-trigger:focus-visible {
outline: 2px solid var(--accent-color, #1a1a1a);
outline-offset: 2px;
border-color: var(--accent-color, #1a1a1a);
}

.wf-tooltiphovercard-trigger:active {
background: var(--background-secondary, #f5f5f5);
}

/* Content container */
.wf-tooltiphovercard-content {
max-width: var(--wf-tooltiphovercard-max-width);
border-radius: var(--border-radius, 8px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
animation: wf-tooltiphovercard-fadein 0.2s ease-out;
pointer-events: none;
}

@keyframes wf-tooltiphovercard-fadein {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}

/* Dark theme */
.wf-tooltiphovercard-content--dark {
background: var(--accent-color, #1a1a1a);
color: var(--accent-text-color, #ffffff);
}

/* Light theme */
.wf-tooltiphovercard-content--light {
background: var(--background-primary, #ffffff);
color: var(--text-primary, #1a1a1a);
border: 1px solid var(--border-color, #e5e5e5);
}

/* Tooltip mode */
.wf-tooltiphovercard-tooltip {
padding: 8px 12px;
font-size: 14px;
line-height: 1.5;
}

/* Hover card mode */
.wf-tooltiphovercard-hovercard {
display: flex;
flex-direction: column;
}

.wf-tooltiphovercard-hovercard-image-wrapper {
width: 100%;
overflow: hidden;
border-radius: var(--border-radius, 8px) var(--border-radius, 8px) 0 0;
}

.wf-tooltiphovercard-hovercard-image {
width: 100%;
height: auto;
display: block;
object-fit: cover;
}

.wf-tooltiphovercard-hovercard-body {
padding: 16px;
}

.wf-tooltiphovercard-hovercard-title {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: 600;
line-height: 1.4;
}

.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-hovercard-title {
color: var(--accent-text-color, #ffffff);
}

.wf-tooltiphovercard-content--light .wf-tooltiphovercard-hovercard-title {
color: var(--text-primary, #1a1a1a);
}

.wf-tooltiphovercard-hovercard-description {
font-size: 14px;
line-height: 1.6;
margin: 0;
}

.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-hovercard-description {
color: var(--accent-text-color, #ffffff);
opacity: 0.9;
}

.wf-tooltiphovercard-content--light .wf-tooltiphovercard-hovercard-description {
color: var(--text-secondary, #737373);
}

.wf-tooltiphovercard-hovercard-description p {
margin: 0 0 8px 0;
}

.wf-tooltiphovercard-hovercard-description p:last-child {
margin-bottom: 0;
}

.wf-tooltiphovercard-hovercard-description strong {
font-weight: 600;
}

.wf-tooltiphovercard-hovercard-description em {
font-style: italic;
}

.wf-tooltiphovercard-hovercard-description a {
text-decoration: underline;
}

.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-hovercard-description a {
color: var(--accent-text-color, #ffffff);
}

.wf-tooltiphovercard-content--light .wf-tooltiphovercard-hovercard-description a {
color: var(--accent-color, #1a1a1a);
}

/* Arrow pointer */
.wf-tooltiphovercard-arrow {
width: 0;
height: 0;
border-style: solid;
}

/* Arrow for dark theme */
.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-arrow--top {
border-width: 6px 6px 0 6px;
border-color: var(--accent-color, #1a1a1a) transparent transparent transparent;
transform: translateX(-6px);
}

.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-arrow--bottom {
border-width: 0 6px 6px 6px;
border-color: transparent transparent var(--accent-color, #1a1a1a) transparent;
transform: translateX(-6px);
}

.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-arrow--left {
border-width: 6px 0 6px 6px;
border-color: transparent transparent transparent var(--accent-color, #1a1a1a);
transform: translateY(-6px);
}

.wf-tooltiphovercard-content--dark .wf-tooltiphovercard-arrow--right {
border-width: 6px 6px 6px 0;
border-color: transparent var(--accent-color, #1a1a1a) transparent transparent;
transform: translateY(-6px);
}

/* Arrow for light theme */
.wf-tooltiphovercard-content--light .wf-tooltiphovercard-arrow--top {
border-width: 6px 6px 0 6px;
border-color: var(--background-primary, #ffffff) transparent transparent transparent;
transform: translateX(-6px);
filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.1));
}

.wf-tooltiphovercard-content--light .wf-tooltiphovercard-arrow--bottom {
border-width: 0 6px 6px 6px;
border-color: transparent transparent var(--background-primary, #ffffff) transparent;
transform: translateX(-6px);
filter: drop-shadow(0 -2px 2px rgba(0, 0, 0, 0.1));
}

.wf-tooltiphovercard-content--light .wf-tooltiphovercard-arrow--left {
border-width: 6px 0 6px 6px;
border-color: transparent transparent transparent var(--background-primary, #ffffff);
transform: translateY(-6px);
filter: drop-shadow(2px 0 2px rgba(0, 0, 0, 0.1));
}

.wf-tooltiphovercard-content--light .wf-tooltiphovercard-arrow--right {
border-width: 6px 6px 6px 0;
border-color: transparent var(--background-primary, #ffffff) transparent transparent;
transform: translateY(-6px);
filter: drop-shadow(-2px 0 2px rgba(0, 0, 0, 0.1));
}
Loading