diff --git a/ivette/src/dome/renderer/text/richtext.tsx b/ivette/src/dome/renderer/text/richtext.tsx
index 93d1934a6fc93e802cfcaa4e72795f5085e7b855..a78353fff8101d4ac008ff0e6e2cd065473562a2 100644
--- a/ivette/src/dome/renderer/text/richtext.tsx
+++ b/ivette/src/dome/renderer/text/richtext.tsx
@@ -439,9 +439,7 @@ Viewport.pack(
 /* --- Hovering Listener                                                  --- */
 /* -------------------------------------------------------------------------- */
 
-export type HoverCallback = (pos: Position | null) => void;
-
-const OnHover = new Field<HoverCallback|null>(null);
+export type MouseCallback = (pos: Position | null, evt: MouseEvent) => void;
 
 function getPosition(evt: MouseEvent, view: CM.EditorView): Position | null
 {
@@ -461,15 +459,42 @@ function getPosition(evt: MouseEvent, view: CM.EditorView): Position | null
   return null;
 }
 
-OnHover.pack(
+class MouseCallbackField extends Field<MouseCallback|null> {
+  constructor() {
+    super(null);
+    this.callback = this.callback.bind(this);
+  }
+
+  callback(evt: MouseEvent, view: CM.EditorView): boolean {
+    const fn = view.state.field(this.field);
+    if (fn) {
+      const pos = getPosition(evt, view);
+      if (fn) fn(pos, evt);
+    }
+    return false;
+  }
+}
+
+const OnClick = new MouseCallbackField();
+const OnPopup = new MouseCallbackField();
+const OnHover = new MouseCallbackField();
+const OnDouble = new MouseCallbackField();
+
+const MouseEvents : CS.Extension = [
+  OnClick,
+  OnHover,
+  OnPopup,
+  OnDouble,
   CM.EditorView.domEventHandlers({
-    mousemove: _.debounce(
-      (evt: MouseEvent, view: CM.EditorView) => {
-        const fn = view.state.field(OnHover.field);
-        if (fn !== null) fn(getPosition(evt, view));
-        return false;
-    }, 10)
-}));
+    click: (evt: MouseEvent, view: CM.EditorView) => {
+      OnClick.callback(evt, view);
+      if (evt.detail > 1) OnDouble.callback(evt, view);
+      return false;
+    },
+    contextmenu: OnPopup.callback,
+    mousemove: _.debounce(OnHover.callback, 10),
+  }),
+];
 
 /* -------------------------------------------------------------------------- */
 /* --- Decorations                                                        --- */
@@ -763,8 +788,8 @@ function createView(parent: Element): CM.EditorView {
     ReadOnly,
     OnChange,
     OnSelect,
-    OnHover,
     Viewport,
+    MouseEvents,
     Decorations,
   ];
   const state = CS.EditorState.create({ extensions });
@@ -782,7 +807,10 @@ export interface TextViewProps {
   selection?: Range;
   onViewport?: SelectionCallback;
   onSelection?: SelectionCallback;
-  onHover?: HoverCallback;
+  onClick?: MouseCallback;
+  onPopup?: MouseCallback;
+  onHover?: MouseCallback;
+  onDoubleClick?: MouseCallback;
   decorations?: Decorations;
   lineNumbers?: boolean;
   showCurrentLine?: boolean;
@@ -807,19 +835,25 @@ export function TextView(props: TextViewProps) : JSX.Element {
 
   // ---- Fields Props
   const {
+    onClick = null,
+    onPopup = null,
     onHover = null,
     onChange = null,
     readOnly = false,
     onViewport: onReview = null,
     onSelection: onSelect = null,
+    onDoubleClick: onDouble = null,
     lineNumbers: lines,
     showCurrentLine: active,
   } = props;
+  React.useEffect(() => OnClick.dispatch(view, onClick), [view, onClick]);
+  React.useEffect(() => OnPopup.dispatch(view, onPopup), [view, onPopup]);
   React.useEffect(() => OnHover.dispatch(view, onHover), [view, onHover]);
-  React.useEffect(() => ReadOnly.dispatch(view, readOnly), [view, readOnly]);
+  React.useEffect(() => OnDouble.dispatch(view, onDouble), [view, onDouble]);
   React.useEffect(() => OnChange.dispatch(view, onChange), [view, onChange]);
   React.useEffect(() => OnSelect.dispatch(view, onSelect), [view, onSelect]);
   React.useEffect(() => Viewport.dispatch(view, onReview), [view, onReview]);
+  React.useEffect(() => ReadOnly.dispatch(view, readOnly), [view, readOnly]);
   React.useEffect(() => ActiveLine.dispatch(view, active), [view, active]);
   React.useEffect(() => LineNumbers.dispatch(view, lines), [view, lines]);
 
diff --git a/ivette/src/sandbox/text.tsx b/ivette/src/sandbox/text.tsx
index 4da3fd984a0e46fdf79fcfb6cfd37473352de8df..6b588b943c30365dd6147c4809a18460bc61e25f 100644
--- a/ivette/src/sandbox/text.tsx
+++ b/ivette/src/sandbox/text.tsx
@@ -56,6 +56,7 @@ function UseText(): JSX.Element {
   const [s, onSelection] = React.useState(emptySelection);
   const [v, onViewport] = React.useState(emptySelection);
   const [h, onHover] = React.useState<Position | null>(null);
+  const [evt, setEvent] = React.useState('');
   const proxy = React.useMemo(() => new TextProxy(), []);
   const buffer = React.useMemo(() => new TextBuffer(), []);
   const text = useProxy ? proxy : buffer;
@@ -120,6 +121,32 @@ function UseText(): JSX.Element {
     return [...decorations, { line: h.line, className: 'hover' }];
   }, [decorations, h]);
 
+  const clearEvent = React.useCallback(() => setEvent(''), []);
+  const triggerCancelEvent = Dome.useDebounced(clearEvent, 1000);
+
+  const onClick = React.useCallback(
+    (pos: Position | null, evt: MouseEvent) => {
+      const name =
+        evt.altKey ? 'Alt-Click' :
+        evt.ctrlKey ? 'Ctrl-Click' :
+        evt.metaKey ? 'Meta-Click' :
+        'Click';
+      setEvent(`${name} ${pos ? pos.offset : 'null'}`);
+      triggerCancelEvent();
+    }, [triggerCancelEvent]);
+
+  const onPopup = React.useCallback(
+    (pos: Position | null) => {
+      setEvent(`Popup ${pos ? pos.offset : 'null'}`);
+      triggerCancelEvent();
+    }, [triggerCancelEvent]);
+
+  const onDoubleClick = React.useCallback(
+    (pos: Position | null) => {
+      setEvent(`Double-Click ${pos ? pos.offset : 'null'}`);
+      triggerCancelEvent();
+    }, [triggerCancelEvent]);
+
   return (
     <>
       <ToolBar>
@@ -184,17 +211,23 @@ function UseText(): JSX.Element {
         onChange={onChange}
         onSelection={onSelection}
         onHover={onHover}
+        onClick={onClick}
+        onPopup={onPopup}
+        onDoubleClick={onDoubleClick}
         onViewport={onViewport}
         decorations={allDecorations}
         lineNumbers={useLines}
         showCurrentLine={useCurrent}
       />
       <ToolBar>
-        <Code label={`Offset ${s.offset}-${s.offset + s.length} / ${length}`} />
-        <Code label={`Line ${s.fromLine}-${s.toLine} / ${lines}`} />
+        <Code label={`Length ${length}`} />
+        <Code label={`Lines ${lines}`} />
+        <Code label={`Offset ${s.offset}-${s.offset + s.length}`} />
+        <Code label={`Line ${s.fromLine}-${s.toLine}`} />
         <Code label={`View ${v.fromLine}-${v.toLine}`} />
         <Code label={`Hover ${h ? h.offset : '-'}:${h ? h.line : '-'}`} />
         <Filler />
+        <Code>{evt}</Code>
         <Code>{`Changes: ${changes}`}</Code>
       </ToolBar>
     </>