diff --git a/examples/06-custom-schema/05-equation/.bnexample.json b/examples/06-custom-schema/05-equation/.bnexample.json
new file mode 100644
index 0000000000..896230e294
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/.bnexample.json
@@ -0,0 +1,11 @@
+{
+  "playground": true,
+  "docs": false,
+  "author": "jkcs",
+  "tags": ["Equation", "Inline Equation", "Custom Schemas", "Latex", "Katex"],
+  "dependencies": {
+    "katex": "^0.16.11",
+    "@types/katex": "^0.16.7",
+    "react-icons": "^5.2.1"
+  }
+}
diff --git a/examples/06-custom-schema/05-equation/App.tsx b/examples/06-custom-schema/05-equation/App.tsx
new file mode 100644
index 0000000000..f5c7c4215a
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/App.tsx
@@ -0,0 +1,90 @@
+import {
+  BlockNoteSchema,
+  defaultInlineContentSpecs,
+  filterSuggestionItems,
+} from "@blocknote/core";
+import "@blocknote/core/fonts/inter.css";
+import { BlockNoteView } from "@blocknote/mantine";
+import "@blocknote/mantine/style.css";
+import {
+  SuggestionMenuController,
+  getDefaultReactSlashMenuItems,
+  useCreateBlockNote,
+} from "@blocknote/react";
+import { RiFormula } from "react-icons/ri";
+
+import { InlineEquation } from "./Equation";
+
+// Our schema with block specs, which contain the configs and implementations for blocks
+// that we want our editor to use.
+const schema = BlockNoteSchema.create({
+  inlineContentSpecs: {
+    ...defaultInlineContentSpecs,
+    inlineEquation: InlineEquation,
+  },
+});
+
+const insertInlineEquation = (editor: typeof schema.BlockNoteEditor) => ({
+  icon: <RiFormula size={18} />,
+  title: "Inline Equation",
+  key: "inlineEquation",
+  subtext: "Insert mathematical symbols in text.",
+  aliases: ["equation", "latex", "katex"],
+  group: "Other",
+  onItemClick: () => {
+    editor.insertInlineContent([
+      {
+        type: "inlineEquation",
+      },
+      " ", // add a space after the mention
+    ]);
+  },
+});
+
+export default function App() {
+  const editor = useCreateBlockNote({
+    schema,
+    initialContent: [
+      {
+        type: "paragraph",
+        content: [
+          "This is an example inline equation ",
+          {
+            type: "inlineEquation",
+            props: {
+              content: "c = \\pm\\sqrt{a^2 + b^2}",
+            },
+          },
+        ],
+      },
+      {
+        type: "paragraph",
+        content: "Press the '/' key to open the Slash Menu and add another",
+      },
+      {
+        type: "paragraph",
+      },
+      {
+        type: "paragraph",
+      },
+    ],
+  });
+
+  // Renders the editor instance.
+  return (
+    <BlockNoteView editor={editor} slashMenu={false}>
+      <SuggestionMenuController
+        triggerCharacter={"/"}
+        getItems={async (query: any) =>
+          filterSuggestionItems(
+            [
+              ...getDefaultReactSlashMenuItems(editor),
+              insertInlineEquation(editor),
+            ],
+            query
+          )
+        }
+      />
+    </BlockNoteView>
+  );
+}
diff --git a/examples/06-custom-schema/05-equation/Equation.tsx b/examples/06-custom-schema/05-equation/Equation.tsx
new file mode 100644
index 0000000000..512efa369c
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/Equation.tsx
@@ -0,0 +1,250 @@
+import { InlineContentFromConfig } from "@blocknote/core";
+import {
+  createReactInlineContentSpec,
+  useBlockNoteEditor,
+  useComponentsContext,
+} from "@blocknote/react";
+import { Node as TipTapNode } from "@tiptap/pm/model";
+import { NodeViewWrapper } from "@tiptap/react";
+import katex from "katex";
+import "katex/dist/katex.min.css";
+import {
+  ChangeEvent,
+  MouseEvent as ReactMouseEvent,
+  TextareaHTMLAttributes,
+  forwardRef,
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+} from "react";
+import { AiOutlineEnter } from "react-icons/ai";
+import "./styles.css";
+
+const TextareaView = forwardRef<
+  HTMLTextAreaElement,
+  {
+    autofocus?: boolean;
+  } & TextareaHTMLAttributes<HTMLTextAreaElement>
+>((props, ref) => {
+  const { autofocus, ...rest } = props;
+  useEffect(() => {
+    if (autofocus && ref && typeof ref !== "function" && ref.current) {
+      ref.current.setSelectionRange(0, ref.current.value.length);
+      ref.current.focus();
+    }
+  }, [autofocus, ref]);
+
+  return (
+    <textarea
+      ref={ref}
+      className={"equation-textarea"}
+      value={props.value}
+      onChange={props.onChange}
+      {...rest}
+    />
+  );
+});
+
+export const InlineEquationView = (props: {
+  inlineContent: InlineContentFromConfig<typeof InlineEquation.config, any>;
+  node: TipTapNode;
+  isSelected: boolean;
+}) => {
+  const content = props.inlineContent.props.content;
+  const nodeSize = props.node.nodeSize;
+  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
+  const contentRef = useRef<HTMLElement | null>(null);
+  const containerRef = useRef<HTMLElement | null>(null);
+
+  const Components = useComponentsContext()!;
+  const editor = useBlockNoteEditor();
+  const html = useMemo(
+    () =>
+      katex.renderToString(content, {
+        throwOnError: false,
+      }),
+    [content]
+  );
+
+  const getTextareaEdge = () => {
+    const $textarea = textareaRef.current;
+    if (!$textarea) {
+      return {};
+    }
+
+    return {
+      isLeftEdge:
+        $textarea.selectionStart === 0 && $textarea.selectionEnd === 0,
+      isRightEdge:
+        $textarea.selectionStart === $textarea.value.length &&
+        $textarea.selectionEnd === $textarea.value.length,
+    };
+  };
+
+  const getPos = useCallback((): number => {
+    let position = 0;
+
+    editor._tiptapEditor.state.doc.descendants(
+      (node: TipTapNode, pos: number) => {
+        if (node === props.node) {
+          position = pos;
+          return false;
+        }
+      }
+    );
+
+    return position;
+  }, [editor, props.node]);
+
+  const handleEnter = useCallback(
+    (event: ReactMouseEvent | React.KeyboardEvent) => {
+      event.preventDefault();
+      const pos = getPos();
+      if (!content) {
+        // TODO: implement BlockNote API to easily delete inline content
+        const node = props.node;
+        const view = editor._tiptapEditor.view;
+
+        const tr = view.state.tr.delete(pos, pos + node.nodeSize);
+
+        view.dispatch(tr);
+        editor._tiptapEditor.commands.setTextSelection(pos);
+      } else {
+        // TODO: implement BlockNote API to easily update cursor position
+        editor._tiptapEditor.commands.setTextSelection(pos + nodeSize);
+      }
+      editor.focus();
+    },
+    [content, editor, getPos, nodeSize, props.node]
+  );
+
+  const handleMenuNavigationKeys = useCallback(
+    (event: React.KeyboardEvent) => {
+      const textareaEdge = getTextareaEdge();
+      const pos = getPos();
+
+      if (event.key === "ArrowLeft") {
+        if (textareaEdge.isLeftEdge) {
+          // TODO: implement BlockNote API to set cursor position
+          event.preventDefault();
+          editor.focus();
+          editor._tiptapEditor.commands.setTextSelection(pos);
+        }
+        return true;
+      }
+
+      if (event.key === "ArrowRight") {
+        if (textareaEdge.isRightEdge) {
+          // TODO: implement BlockNote API to set cursor position
+          event.preventDefault();
+          editor.focus();
+          editor._tiptapEditor.commands.setTextSelection(pos + nodeSize);
+        }
+        return true;
+      }
+
+      if (event.key === "Enter" && props.isSelected) {
+        handleEnter(event);
+        return true;
+      }
+
+      return false;
+    },
+    [editor, getPos, handleEnter, nodeSize, props.isSelected]
+  );
+
+  // TODO: implement BlockNote API to easily update inline content
+  const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
+    const val = e.target.value;
+    const pos = getPos();
+    const node = props.node;
+    const view = editor._tiptapEditor.view;
+
+    const tr = view.state.tr.replaceWith(
+      pos,
+      pos + node.nodeSize,
+      view.state.schema.nodes.inlineEquation.create(
+        {
+          ...node.attrs,
+          content: val || "",
+        },
+        null
+      )
+    );
+
+    view.dispatch(tr);
+  };
+
+  return (
+    <NodeViewWrapper as={"span"} ref={containerRef}>
+      <Components.Generic.Popover.Root opened={props.isSelected}>
+        <Components.Generic.Popover.Trigger>
+          <span
+            className={"equation " + (props.isSelected ? "focus" : "")}
+            ref={contentRef}>
+            {!content ? (
+              <span className={"equation-empty"}>New Equation</span>
+            ) : (
+              <span
+                className={"equation-content"}
+                dangerouslySetInnerHTML={{ __html: html }}></span>
+            )}
+          </span>
+        </Components.Generic.Popover.Trigger>
+        <Components.Generic.Popover.Content
+          className={"bn-popover-content bn-form-popover"}
+          variant={"form-popover"}>
+          <label className={"equation-label"}>
+            <TextareaView
+              placeholder={"c^2 = a^2 + b^2"}
+              ref={textareaRef}
+              autofocus
+              value={content}
+              onChange={handleChange}
+              onKeyDown={handleMenuNavigationKeys}
+            />
+            <span onClick={handleEnter} className={"equation-enter"}>
+              <AiOutlineEnter />
+            </span>
+          </label>
+        </Components.Generic.Popover.Content>
+      </Components.Generic.Popover.Root>
+    </NodeViewWrapper>
+  );
+};
+
+export const InlineEquation = createReactInlineContentSpec(
+  {
+    type: "inlineEquation",
+    propSchema: {
+      content: {
+        default: "",
+      },
+    },
+    content: "none",
+    // copy content
+    renderHTML: (props) => {
+      const { HTMLAttributes, node } = props;
+      const dom = document.createElement("span");
+      dom.setAttribute("data-inline-content-type", "inlineEquation");
+      Object.keys(HTMLAttributes).forEach((key) => {
+        dom.setAttribute(key, HTMLAttributes[key]);
+      });
+      dom.innerText = node.attrs.content;
+
+      return { dom };
+    },
+  },
+  {
+    render: (props) => {
+      return (
+        <InlineEquationView
+          node={props.node}
+          inlineContent={props.inlineContent}
+          isSelected={props.isSelected}
+        />
+      );
+    },
+  }
+);
diff --git a/examples/06-custom-schema/05-equation/README.md b/examples/06-custom-schema/05-equation/README.md
new file mode 100644
index 0000000000..1d40f6f5a1
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/README.md
@@ -0,0 +1,11 @@
+# Inline Equation
+
+In this example, we create a custom `Inline Equation`
+
+**Try it out:** Press the "/" key to open the Slash Menu and insert an `Equation` block!
+
+**Relevant Docs:**
+
+- [Custom Blocks](/docs/custom-schemas/custom-blocks)
+- [Changing Slash Menu Items](/docs/ui-components/suggestion-menus#changing-slash-menu-items)
+- [Editor Setup](/docs/editor-basics/setup)
diff --git a/examples/06-custom-schema/05-equation/index.html b/examples/06-custom-schema/05-equation/index.html
new file mode 100644
index 0000000000..772555bb29
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/index.html
@@ -0,0 +1,14 @@
+<html lang="en">
+  <head>
+    <script>
+      <!-- AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY -->
+    </script>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Inline Equation</title>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="./main.tsx"></script>
+  </body>
+</html>
diff --git a/examples/06-custom-schema/05-equation/main.tsx b/examples/06-custom-schema/05-equation/main.tsx
new file mode 100644
index 0000000000..f88b490fbd
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/main.tsx
@@ -0,0 +1,11 @@
+// AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY
+import React from "react";
+import { createRoot } from "react-dom/client";
+import App from "./App";
+
+const root = createRoot(document.getElementById("root")!);
+root.render(
+  <React.StrictMode>
+    <App />
+  </React.StrictMode>
+);
diff --git a/examples/06-custom-schema/05-equation/package.json b/examples/06-custom-schema/05-equation/package.json
new file mode 100644
index 0000000000..4751728ce7
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "@blocknote/example-equation",
+  "description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY",
+  "private": true,
+  "version": "0.12.4",
+  "scripts": {
+    "start": "vite",
+    "dev": "vite",
+    "build": "tsc && vite build",
+    "preview": "vite preview",
+    "lint": "eslint . --max-warnings 0"
+  },
+  "dependencies": {
+    "@blocknote/core": "latest",
+    "@blocknote/react": "latest",
+    "@blocknote/ariakit": "latest",
+    "@blocknote/mantine": "latest",
+    "@blocknote/shadcn": "latest",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
+    "katex": "^0.16.11",
+    "@types/katex": "^0.16.7",
+    "react-icons": "^5.2.1"
+  },
+  "devDependencies": {
+    "@types/react": "^18.0.25",
+    "@types/react-dom": "^18.0.9",
+    "@vitejs/plugin-react": "^4.3.1",
+    "eslint": "^8.10.0",
+    "vite": "^5.3.4"
+  },
+  "eslintConfig": {
+    "extends": [
+      "../../../.eslintrc.js"
+    ]
+  },
+  "eslintIgnore": [
+    "dist"
+  ]
+}
\ No newline at end of file
diff --git a/examples/06-custom-schema/05-equation/styles.css b/examples/06-custom-schema/05-equation/styles.css
new file mode 100644
index 0000000000..3507e3df3b
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/styles.css
@@ -0,0 +1,62 @@
+.equation-content {
+  caret-color: rgb(55, 53, 47);
+  padding: 2px 2px;
+  border-radius: 4px;
+  transform: translate3d(-4px, 0, 0);
+  margin-right: -4px;
+  white-space: pre;
+}
+
+.equation.focus .equation-content {
+  background: rgba(37, 135, 231, 0.12);
+}
+
+.equation .equation-empty {
+  white-space: nowrap;
+  font-size: 12px;
+  background: rgb(207, 207, 207);
+  caret-color: rgb(55, 53, 47);
+  vertical-align: top;
+  padding: 2px 4px;
+  border-radius: 4px;
+  transform: translate3d(-4px, 0, 0);
+  margin-right: -8px;
+}
+
+.equation-label {
+  display: flex;
+  align-items: flex-start;
+  justify-content: flex-start;
+  padding: 4px;
+}
+
+.equation-textarea {
+  min-width: 200px;
+  margin-right: 10px;
+  outline: none;
+  border: none;
+  font-size: 14px;
+}
+
+.equation-enter {
+  user-select: none;
+  cursor: pointer;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  white-space: nowrap;
+  height: 28px;
+  border-radius: 4px;
+  box-shadow: rgba(15, 15, 15, 0.1) 0 0 0 1px inset,
+    rgba(15, 15, 15, 0.1) 0 1px 2px;
+  background: rgb(35, 131, 226);
+  color: white;
+  fill: white;
+  line-height: 1.2;
+  padding-left: 12px;
+  padding-right: 12px;
+  font-size: 14px;
+  font-weight: 500;
+  align-self: flex-start;
+}
diff --git a/examples/06-custom-schema/05-equation/tsconfig.json b/examples/06-custom-schema/05-equation/tsconfig.json
new file mode 100644
index 0000000000..1bd8ab3c57
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/tsconfig.json
@@ -0,0 +1,36 @@
+{
+  "__comment": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY",
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "lib": [
+      "DOM",
+      "DOM.Iterable",
+      "ESNext"
+    ],
+    "allowJs": false,
+    "skipLibCheck": true,
+    "esModuleInterop": false,
+    "allowSyntheticDefaultImports": true,
+    "strict": true,
+    "forceConsistentCasingInFileNames": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "composite": true
+  },
+  "include": [
+    "."
+  ],
+  "__ADD_FOR_LOCAL_DEV_references": [
+    {
+      "path": "../../../packages/core/"
+    },
+    {
+      "path": "../../../packages/react/"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/06-custom-schema/05-equation/vite.config.ts b/examples/06-custom-schema/05-equation/vite.config.ts
new file mode 100644
index 0000000000..f62ab20bc2
--- /dev/null
+++ b/examples/06-custom-schema/05-equation/vite.config.ts
@@ -0,0 +1,32 @@
+// AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY
+import react from "@vitejs/plugin-react";
+import * as fs from "fs";
+import * as path from "path";
+import { defineConfig } from "vite";
+// import eslintPlugin from "vite-plugin-eslint";
+// https://vitejs.dev/config/
+export default defineConfig((conf) => ({
+  plugins: [react()],
+  optimizeDeps: {},
+  build: {
+    sourcemap: true,
+  },
+  resolve: {
+    alias:
+      conf.command === "build" ||
+      !fs.existsSync(path.resolve(__dirname, "../../packages/core/src"))
+        ? {}
+        : ({
+            // Comment out the lines below to load a built version of blocknote
+            // or, keep as is to load live from sources with live reload working
+            "@blocknote/core": path.resolve(
+              __dirname,
+              "../../packages/core/src/"
+            ),
+            "@blocknote/react": path.resolve(
+              __dirname,
+              "../../packages/react/src/"
+            ),
+          } as any),
+  },
+}));
diff --git a/package-lock.json b/package-lock.json
index e3d7c46a74..9848e8f358 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17763,13 +17763,14 @@
       "dev": true
     },
     "node_modules/katex": {
-      "version": "0.16.10",
-      "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.10.tgz",
-      "integrity": "sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==",
+      "version": "0.16.11",
+      "resolved": "https://registry.npmmirror.com/katex/-/katex-0.16.11.tgz",
+      "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==",
       "funding": [
         "https://opencollective.com/katex",
         "https://github.com/sponsors/katex"
       ],
+      "license": "MIT",
       "dependencies": {
         "commander": "^8.3.0"
       },
@@ -28840,6 +28841,7 @@
         "@mantine/core": "^7.10.1",
         "@mui/icons-material": "^5.16.1",
         "@mui/material": "^5.16.1",
+        "@types/katex": "^0.16.7",
         "@uppy/core": "^3.13.1",
         "@uppy/dashboard": "^3.9.1",
         "@uppy/drag-drop": "^3.1.1",
@@ -28851,6 +28853,7 @@
         "@uppy/status-bar": "^3.1.1",
         "@uppy/webcam": "^3.4.2",
         "@uppy/xhr-upload": "^3.4.0",
+        "katex": "^0.16.11",
         "react": "^18.3.1",
         "react-dom": "^18.3.1",
         "react-icons": "^5.2.1",
diff --git a/packages/core/src/schema/inlineContent/types.ts b/packages/core/src/schema/inlineContent/types.ts
index 5ef62f593e..708bab857d 100644
--- a/packages/core/src/schema/inlineContent/types.ts
+++ b/packages/core/src/schema/inlineContent/types.ts
@@ -1,4 +1,6 @@
 import { Node } from "@tiptap/core";
+import { DOMOutputSpec } from "@tiptap/pm/model";
+import { Node as ProseMirrorNode } from "prosemirror-model";
 import { PropSchema, Props } from "../propTypes";
 import { StyleSchema, Styles } from "../styles/types";
 
@@ -6,6 +8,10 @@ export type CustomInlineContentConfig = {
   type: string;
   content: "styled" | "none"; // | "plain"
   readonly propSchema: PropSchema;
+  renderHTML?: (props: {
+    node: ProseMirrorNode;
+    HTMLAttributes: Record<string, any>;
+  }) => DOMOutputSpec;
   // content: "inline" | "none" | "table";
 };
 // InlineContentConfig contains the "schema" info about an InlineContent type
diff --git a/packages/mantine/src/popover/Popover.tsx b/packages/mantine/src/popover/Popover.tsx
index b81f842e65..28af93afa9 100644
--- a/packages/mantine/src/popover/Popover.tsx
+++ b/packages/mantine/src/popover/Popover.tsx
@@ -11,7 +11,7 @@ import { forwardRef } from "react";
 export const Popover = (
   props: ComponentProps["Generic"]["Popover"]["Root"]
 ) => {
-  const { children, opened, position, ...rest } = props;
+  const { children, opened, onChange, position, ...rest } = props;
 
   assertEmpty(rest);
 
@@ -20,7 +20,8 @@ export const Popover = (
       withinPortal={false}
       zIndex={10000}
       opened={opened}
-      position={position}>
+      position={position}
+      onChange={onChange}>
       {children}
     </MantinePopover>
   );
diff --git a/packages/react/package.json b/packages/react/package.json
index b7b27abcec..f229ba6908 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -55,6 +55,7 @@
     "@floating-ui/react": "^0.26.4",
     "@tiptap/core": "^2.5.0",
     "@tiptap/react": "^2.5.0",
+    "@tiptap/pm": "^2.5.0",
     "lodash.merge": "^4.6.2",
     "react": "^18",
     "react-dom": "^18",
diff --git a/packages/react/src/editor/ComponentsContext.tsx b/packages/react/src/editor/ComponentsContext.tsx
index 7a46df4549..24d6861ab4 100644
--- a/packages/react/src/editor/ComponentsContext.tsx
+++ b/packages/react/src/editor/ComponentsContext.tsx
@@ -9,8 +9,8 @@ import {
   useContext,
 } from "react";
 
-import { DefaultReactSuggestionItem } from "../components/SuggestionMenu/types";
 import { DefaultReactGridSuggestionItem } from "../components/SuggestionMenu/GridSuggestionMenu/types";
+import { DefaultReactSuggestionItem } from "../components/SuggestionMenu/types";
 
 export type ComponentProps = {
   FormattingToolbar: {
@@ -241,6 +241,7 @@ export type ComponentProps = {
         children?: ReactNode;
         opened?: boolean;
         position?: "top" | "right" | "bottom" | "left";
+        onChange?: (open: boolean) => void;
       };
       Content: {
         className?: string;
diff --git a/packages/react/src/schema/ReactInlineContentSpec.tsx b/packages/react/src/schema/ReactInlineContentSpec.tsx
index 27999dcfea..68243236ae 100644
--- a/packages/react/src/schema/ReactInlineContentSpec.tsx
+++ b/packages/react/src/schema/ReactInlineContentSpec.tsx
@@ -21,6 +21,7 @@ import {
   ReactNodeViewRenderer,
 } from "@tiptap/react";
 // import { useReactNodeView } from "@tiptap/react/dist/packages/react/src/useReactNodeView";
+import { Node } from "@tiptap/pm/model";
 import { FC } from "react";
 import { renderToDOMSpec } from "./@util/ReactRenderUtil";
 
@@ -35,6 +36,8 @@ export type ReactInlineContentImplementation<
   render: FC<{
     inlineContent: InlineContentFromConfig<T, S>;
     contentRef: (node: HTMLElement | null) => void;
+    node: Node;
+    isSelected: boolean;
   }>;
   // TODO?
   // toExternalHTML?: FC<{
@@ -91,7 +94,7 @@ export function createReactInlineContentSpec<
     name: inlineContentConfig.type as T["type"],
     inline: true,
     group: "inline",
-    selectable: inlineContentConfig.content === "styled",
+    selectable: true, //inlineContentConfig.content === "styled",
     atom: inlineContentConfig.content === "none",
     content: (inlineContentConfig.content === "styled"
       ? "inline*"
@@ -109,7 +112,10 @@ export function createReactInlineContentSpec<
       return getInlineContentParseRules(inlineContentConfig);
     },
 
-    renderHTML({ node }) {
+    renderHTML({ node, ...args }) {
+      if (inlineContentConfig.renderHTML) {
+        return inlineContentConfig.renderHTML({ node, ...args });
+      }
       const editor = this.options.editor;
 
       const ic = nodeToCustomInlineContent(
@@ -119,7 +125,14 @@ export function createReactInlineContentSpec<
       ) as any as InlineContentFromConfig<T, S>; // TODO: fix cast
       const Content = inlineContentImplementation.render;
       const output = renderToDOMSpec(
-        (refCB) => <Content inlineContent={ic} contentRef={refCB} />,
+        (refCB) => (
+          <Content
+            inlineContent={ic}
+            contentRef={refCB}
+            node={node}
+            isSelected={false}
+          />
+        ),
         editor
       );
 
@@ -131,7 +144,6 @@ export function createReactInlineContentSpec<
       );
     },
 
-    // TODO: needed?
     addNodeView() {
       const editor = this.options.editor;
       return (props) =>
@@ -141,6 +153,13 @@ export function createReactInlineContentSpec<
             const ref = (NodeViewContent({}) as any).ref;
 
             const Content = inlineContentImplementation.render;
+
+            const isSelected =
+              props.selected &&
+              props.editor.state.selection.from === props.getPos() &&
+              props.editor.state.selection.to ===
+                props.getPos() + props.node.nodeSize;
+
             return (
               <InlineContentWrapper
                 inlineContentProps={props.node.attrs as Props<T["propSchema"]>}
@@ -148,6 +167,7 @@ export function createReactInlineContentSpec<
                 propSchema={inlineContentConfig.propSchema}>
                 <Content
                   contentRef={ref}
+                  node={props.node}
                   inlineContent={
                     nodeToCustomInlineContent(
                       props.node,
@@ -155,6 +175,7 @@ export function createReactInlineContentSpec<
                       editor.schema.styleSchema
                     ) as any as InlineContentFromConfig<T, S> // TODO: fix cast
                   }
+                  isSelected={isSelected}
                 />
               </InlineContentWrapper>
             );
diff --git a/playground/package.json b/playground/package.json
index 0992b1d34f..14ec4b6db9 100644
--- a/playground/package.json
+++ b/playground/package.json
@@ -25,6 +25,7 @@
     "@mantine/core": "^7.10.1",
     "@mui/icons-material": "^5.16.1",
     "@mui/material": "^5.16.1",
+    "@types/katex": "^0.16.7",
     "@uppy/core": "^3.13.1",
     "@uppy/dashboard": "^3.9.1",
     "@uppy/drag-drop": "^3.1.1",
@@ -36,6 +37,7 @@
     "@uppy/status-bar": "^3.1.1",
     "@uppy/webcam": "^3.4.2",
     "@uppy/xhr-upload": "^3.4.0",
+    "katex": "^0.16.11",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "react-icons": "^5.2.1",
diff --git a/playground/src/examples.gen.tsx b/playground/src/examples.gen.tsx
index 1941512e3f..c8eb80b955 100644
--- a/playground/src/examples.gen.tsx
+++ b/playground/src/examples.gen.tsx
@@ -886,6 +886,33 @@
           "slug": "custom-schema"
         }
       },
+      {
+        "projectSlug": "equation",
+        "fullSlug": "custom-schema/equation",
+        "pathFromRoot": "examples/06-custom-schema/05-equation",
+        "config": {
+          "playground": true,
+          "docs": false,
+          "author": "jkcs",
+          "tags": [
+            "Equation",
+            "Inline Equation",
+            "Custom Schemas",
+            "Latex",
+            "Katex"
+          ],
+          "dependencies": {
+            "katex": "^0.16.11",
+            "@types/katex": "^0.16.7",
+            "react-icons": "^5.2.1"
+          } as any
+        },
+        "title": "Inline Equation",
+        "group": {
+          "pathFromRoot": "examples/06-custom-schema",
+          "slug": "custom-schema"
+        }
+      },
       {
         "projectSlug": "react-custom-blocks",
         "fullSlug": "custom-schema/react-custom-blocks",