Core SDC only
Each React widget is a normal Single Directory Component (component.yml + twig). Place it with include, embed or a render array.
No contrib modules. Vite build. Data from Views through views_better_rest. Works with Drupal ajax, BigPipe and hidden tabs.
Recipe explorer on the Umami demo: a Views REST export drives filters, sorting and pager. DevTools (Network, Fetch/XHR) shows the ajax calls.
More in Demos.
A React tooltip as a Drupal component: five small files. Nothing else to register, the build discovers the folder.
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: React Tooltip
status: stable
description: 'A React-based tooltip component that displays helpful text on hover.'
group: Interactive
props:
type: object
properties:
text:
type: string
title: Tooltip Text
description: 'The text to display in the tooltip'
default: 'Tooltip text'
examples:
- 'This is the tooltip text'
required:
- text
slots:
content:
title: Content
description: 'The content that triggers the tooltip when hovered'
examples:
- 'Hover me to see the tooltip'
libraryOverrides:
js:
../../assets/react-tooltip.js: { attributes: { type: module } }
css:
theme:
../../assets/react-tooltip.css: { }
dependencies:
- react_scaffold/react<span {{ attributes.addClass('react-tooltip').setAttribute('data-text', text) }}>{% block content %}{% endblock %}</span>import 'react-tippy/dist/tippy.css';
import {TextWithTooltip} from './TextWithTooltip';
import './react-tooltip.scss'
import { createRoot } from 'react-dom/client';
// Props of the SDC (e.g. 'text') arrive as data-* attributes on the mount element.
(function (Drupal, once) {
const attachTooltip = (element) => {
createRoot(element).render(
<TextWithTooltip text={element.dataset.text} content={element.innerText}/>
);
};
Drupal.behaviors.reactTooltip = {
attach(context) {
once('react', '.react-tooltip', context)
.forEach((element) => executeWhenVisible(element, attachTooltip, "tooltip"))
},
};
})(Drupal, once);import { Tooltip } from "react-tippy";
export const TextWithTooltip = ({ text, content }) => (
<Tooltip
html={<span className="react-tooltip__text">{text}</span>}
className="react-tooltip__container"
position="right"
delay={100}
animateFill={false}
>
{content}
</Tooltip>
);.react-tooltip {
margin-left: .4rem;
margin-right: .4rem;
&__container {
display: flex;
max-width: 20rem;
line-height: 1.5;
padding: .5rem;
}
}
// Umami look for the react-tippy bubble.
.tippy-popper .tippy-tooltip.dark-theme {
background-color: #008068;
font-family: "Source Sans Pro", Verdana, sans-serif;
font-size: .95rem;
border-radius: .35rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, .25);
.tippy-arrow {
border-top-color: #008068;
border-bottom-color: #008068;
border-left-color: #008068;
border-right-color: #008068;
}
}See the full walkthrough and the bigger recipe explorer.