Get started

The form (Solid)

The same state machine, as accessors: every value is a function, so the JSX tracks exactly what it reads.

tsx
import { createBugReport } from "bugbottle/solid";
import { htmlToImage } from "bugbottle/html-to-image"; // optional
import { For, Show, onMount } from "solid-js";

function FeedbackForm() {
  const form = createBugReport({
    endpoint: "/api/feedback",
    screenshot: htmlToImage, // leave out to disable screenshots
  });

  onMount(() => form.open());

  return (
    <form data-bugbottle onSubmit={(e) => (e.preventDefault(), form.submit())}>
      <For each={form.types}>
        {(t) => (
          <button type="button" onClick={() => form.setType(t)}>
            {t}
          </button>
        )}
      </For>

      <textarea value={form.message()} onInput={(e) => form.setMessage(e.currentTarget.value)} />

      <Show when={form.canScreenshot()}>
        <label>
          <input
            type="checkbox"
            checked={form.includeScreenshot()}
            onChange={(e) => form.toggleScreenshot(e.currentTarget.checked)}
          />
          Attach a picture of this page
        </label>
      </Show>
      <Show when={form.screenshot()}>{(src) => <img src={src()} alt="" />}</Show>

      <button type="button" onClick={() => form.pickElement()}>
        {form.isPicking() ? "Click anything to attach it — Esc to stop" : "Point at the element"}
      </button>
      <ul>
        <For each={form.elements()}>
          {(el, i) => (
            <li>
              <code>{el.selector}</code> {el.text}
              <button type="button" onClick={() => form.removeElement(i())}>
                ×
              </button>
            </li>
          )}
        </For>
      </ul>

      <p role="status">{form.statusMessage()}</p>
      <button disabled={form.isSending()}>Send</button>
    </form>
  );
}

The subscription is torn down with the owner the function was called in — the component, normally; call form.destroy() yourself if you called it outside one. solid-js is an optional peer dependency, so nothing about it reaches a project that does not use it.

Edit this page on GitHub