1import { defineRule } from "@oxlint/plugins";
2
3const INTRINSIC_ELEMENT_PATTERN = /^[a-z]/u;
4
5// On these elements the title attribute names the embedded content for
6// accessibility (and does not reliably produce a hover tooltip), so the styled
7// Tooltip component is not a drop-in replacement.
8const TITLE_IS_AN_ACCESSIBLE_NAME = new Set(["embed", "frame", "iframe", "math", "object"]);
9
10export default defineRule({
11 meta: {
12 type: "problem",
13 docs: {
14 description:
15 "Disallow the native title attribute as a tooltip on intrinsic elements; use the styled Tooltip component.",
16 },
17 },
18 create(context) {
19 return {
20 JSXOpeningElement(node) {
21 if (node.name.type !== "JSXIdentifier") return;
22 if (!INTRINSIC_ELEMENT_PATTERN.test(node.name.name)) return;
23 if (TITLE_IS_AN_ACCESSIBLE_NAME.has(node.name.name)) return;
24
25 for (const attribute of node.attributes) {
26 if (attribute.type !== "JSXAttribute") continue;
27 if (attribute.name.type !== "JSXIdentifier") continue;
28 if (attribute.name.name !== "title") continue;
29
30 context.report({
31 node: attribute,
32 message:
33 "Do not use the native title attribute as a tooltip. Use Tooltip + TooltipTrigger + TooltipPopup from components/ui/tooltip.",
34 });
35 }
36 },
37 };
38 },
39});