diff --git a/README.md b/README.md
index c22f0eb..5ed92ea 100644
--- a/README.md
+++ b/README.md
@@ -145,9 +145,10 @@ An attribute starting with `on` will passed to [the event listeners module](http
// { on: { click: f } }
```
-### `list` and `role`
+### `list`, `role`, and `popoverTarget`
-The `list` and the `role` attributes will be passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).
+The `list`, the `role`, and the `popoverTarget` attributes will be passed to [the attributes module](https://github.com/snabbdom/snabbdom#the-attributes-module).
+Note that the attribute names will be lowercased.
```tsx
@@ -155,6 +156,9 @@ The `list` and the `role` attributes will be passed to [the attributes module](h
// { attrs: { list: 'options' } }
+
+
+// { attrs: { popovertarget: 'popover' } }
```
### `$hook`
diff --git a/src/jsx-runtime.test.tsx b/src/jsx-runtime.test.tsx
index 8b419f9..416d1a0 100644
--- a/src/jsx-runtime.test.tsx
+++ b/src/jsx-runtime.test.tsx
@@ -1032,4 +1032,50 @@ describe('automatic runtime', () => {
text: undefined,
});
});
+
+ test('popover API', () => {
+ expect(
+ <>
+
+ Toggle
+
+ Hello, world!
+ >,
+ ).toStrictEqual({
+ children: [
+ {
+ children: undefined,
+ data: {
+ attrs: {
+ popovertarget: 'popover',
+ },
+ props: {
+ popoverTargetAction: 'toggle',
+ },
+ },
+ elm: undefined,
+ key: undefined,
+ sel: 'button',
+ text: 'Toggle',
+ },
+ {
+ children: undefined,
+ data: {
+ props: {
+ popover: 'auto',
+ },
+ },
+ elm: undefined,
+ key: undefined,
+ sel: 'div',
+ text: 'Hello, world!',
+ },
+ ],
+ data: {},
+ elm: undefined,
+ key: undefined,
+ sel: undefined,
+ text: undefined,
+ });
+ });
});
diff --git a/src/jsx-runtime.ts b/src/jsx-runtime.ts
index 5c72861..6b08402 100644
--- a/src/jsx-runtime.ts
+++ b/src/jsx-runtime.ts
@@ -63,6 +63,12 @@ const canonicalizeVNodeData = (orig: VNodeData): VNodeData => {
} else if (key === 'list' || key === 'role') {
data.attrs ??= {};
data.attrs[key] = v;
+ } else if (key === 'popover' && v === true) {
+ data.props ??= {};
+ data.props['popover'] = 'auto';
+ } else if (key === 'popoverTarget') {
+ data.attrs ??= {};
+ data.attrs['popovertarget'] = v;
} else if (key === '$style' || key === 'style') {
data.style = v;
} else if (key.startsWith('$')) {
diff --git a/src/types.ts b/src/types.ts
index ba23c92..6a60fa7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -336,6 +336,7 @@ export declare namespace Internal {
type Dir = 'ltr' | 'rtl' | 'auto' | Whatever;
type EnterKeyHint = 'done' | 'enter' | 'go' | 'next' | 'previous' | 'search' | 'send' | Whatever;
type InputMode = 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search' | Whatever;
+ type Popover = 'auto' | 'manual';
interface Props extends Element.Props {
accessKey?: string | undefined;
@@ -353,6 +354,7 @@ export declare namespace Internal {
noModule?: boolean | undefined;
nonce?: string | undefined;
outerText?: string | undefined;
+ popover?: Popover | true | undefined;
spellcheck?: boolean | undefined;
tabIndex?: number | string | undefined;
title?: string | undefined;
@@ -408,6 +410,7 @@ export declare namespace Internal {
}
namespace HTMLButtonElement {
+ type PopoverTargetAction = 'hide' | 'show' | 'toggle';
type Type = 'button' | 'reset' | 'submit' | Whatever;
interface Props extends HTMLElement.Props {
@@ -419,6 +422,8 @@ export declare namespace Internal {
formNoValidate?: boolean | undefined;
formTarget?: string | undefined;
name?: string | undefined;
+ popoverTarget?: string | undefined;
+ popoverTargetAction?: PopoverTargetAction | undefined;
type?: Type | undefined;
value?: string;
}