#Using JSX in custom directives

6 messages · Page 1 of 1 (latest)

limpid forum
#

Suppose you want to create a convenient tooltip directive that can be easily used by providing only the content of it. This works fine for simple tooltips. However, what if you want to create more complex, custom tooltips? For example, you want to wrap the element as a trigger and use it in combination with a component from libraries like https://kobalte.dev/docs/core/components/tooltip or https://corvu.dev/docs/primitives/tooltip

import { type Accessor, createEffect, createSignal } from "solid-js";
import { render } from "solid-js/web";

export default function tooltip(el: HTMLElement, title: Accessor<string>) {
  createEffect(() => {
    el.title = title();
  });
}

declare module "solid-js" {
  namespace JSX {
    interface DirectiveFunctions {
      tooltip: typeof tooltip;
    }
  }
}

function App() {
  const [count, setCount] = createSignal<number>(0);

  return (
    <button
      onClick={() => setCount((c) => c + 1)}
      use:tooltip="Push to increment count"
    >
      {count()}
    </button>
  );
}

render(() => <App />, document.getElementById("app")!);

https://playground.solidjs.com/anonymous/eb41151c-59ca-460f-aa45-26ea80525e01

Is it possible to use JSX inside the directive to wrap the <button> with a <Tooltip> component?

earnest cypress
#

You cannot directly influence the return value, but you can create a portal for the tooltip and event listeners for the trigger.

limpid forum
earnest cypress
#

Basically, you call Portal({ get children() { return <Tooltip .../> } }).

limpid forum
# earnest cypress Basically, you call `Portal({ get children() { return <Tooltip .../> } })`.

I came up with this. However, it renders the whole element as a <Portal>. Can you render it in the same exact spot?

import { type Accessor, createSignal } from "solid-js";
import { render, Portal } from "solid-js/web";

import { Tooltip } from "@kobalte/core/tooltip";

export default function tooltip(el: HTMLElement, title: Accessor<string>) {
  Portal({
    get children() {
      return (
        <Tooltip>
          <Tooltip.Trigger as={"span"}>{el}</Tooltip.Trigger>
          <Tooltip.Portal>
            <Tooltip.Content>{title()}</Tooltip.Content>
          </Tooltip.Portal>
        </Tooltip>
      );
    },
  });
}

declare module "solid-js" {
  namespace JSX {
    interface DirectiveFunctions {
      tooltip: typeof tooltip;
    }
  }
}

function App() {
  const [count, setCount] = createSignal<number>(0);

  return (
    <button
      onClick={() => setCount((c) => c + 1)}
      use:tooltip="Push to increment count"
    >
      {count()}
    </button>
  );
}

render(() => <App />, document.getElementById("app")!);
earnest cypress
#

Unfortunately, no, but you can use the ref to move the tooltip.