Skip to Content
ExamplesInteraction

Connection Events

Vue Flow emits different events during the connection process that you can use to update your UI or your flow in different ways. The example below demonstrates which events are fired and when.

/* xyflow theme files. Delete these to start from our base */ /* * `@xyflow/vue`'s `colorMode` sets `color-scheme` (light/dark/system) rather than toggling a `.dark` * class, so these tokens use CSS `light-dark(<light>, <dark>)` to follow the resolved scheme instead of a * `.vue-flow.dark` selector. Single values are scheme-independent. */ .vue-flow { --xy-background-color: light-dark(#f7f9fb, #101012); /* Custom Variables */ --xy-theme-selected: #16a34a; --xy-theme-hover: light-dark(#c5c5c5, #7a7d86); --xy-theme-edge-hover: light-dark(black, #f3f4f6); --xy-theme-color-focus: light-dark(#e8e8e8, #4b4e57); /* Built-in Variables see https://vueflow.dev/learn/customization/theming */ /* light-dark() is a <color> function — it must wrap only the color, not the whole border shorthand */ --xy-node-border-default: 1px solid light-dark(#ededed, #303238); /* light-dark() can't split a comma-separated shadow list (wrapping each in a var() doesn't help — the commas re-expand before light-dark parses its args), so the dark shadow is applied via the prefers-color-scheme media query below, which matches `color-scheme: system` (the common case) */ --xy-node-boxshadow-default: 0px 3.54px 4.55px 0px #00000005, 0px 3.54px 4.55px 0px #0000000d, 0px 0.51px 1.01px 0px #0000001a; --xy-node-border-radius-default: 8px; --xy-handle-background-color-default: light-dark(#ffffff, #141519); --xy-handle-border-color-default: light-dark(#aaaaaa, #5a5d66); --xy-edge-label-color-default: light-dark(#505050, #e6e7ea); --xy-node-background-color-default: light-dark(#ffffff, #1a1b1e); --xy-theme-panel-bg: light-dark(#ffffff, #141519); --xy-theme-panel-text: light-dark(#111827, #f3f4f6); --xy-theme-resize-handle-bg: light-dark(#ffffff, #141519); --xy-theme-focus-border: light-dark(#d9d9d9, #5f6470); --xy-theme-muted-bg: light-dark(#f3f4f6, #24262c); --xy-theme-subtle-border: light-dark(#d1d5db, #3f434c); /* example UI tokens (consumed by the .xy-theme__* helpers below) */ --color-primary: #16a34a; --color-background: light-dark(#fefefe, #1a1b1e); --color-hover-bg: light-dark(#f6f6f6, #24262c); --color-disabled: light-dark(#76797e, #8b9099); } .vue-flow { background-color: var(--xy-background-color); } /* dark node shadow — the one token light-dark() can't express (see above) */ @media (prefers-color-scheme: dark) { .vue-flow { --xy-node-boxshadow-default: 0px 6px 18px 0px rgba(0, 0, 0, 0.35), 0px 2px 6px 0px rgba(0, 0, 0, 0.3), 0px 1px 2px 0px rgba(0, 0, 0, 0.35); } } /* Customizing Default Theming */ .vue-flow__node { box-shadow: var(--xy-node-boxshadow-default); border-radius: var(--xy-node-border-radius-default); background-color: var(--xy-node-background-color-default); display: flex; justify-content: center; align-items: center; text-align: center; padding: 10px; font-size: 12px; flex-direction: column; border: var(--xy-node-border-default); color: var(--xy-node-color, var(--xy-node-color-default)); } .vue-flow__node.selectable:focus { box-shadow: 0px 0px 0px 4px var(--xy-theme-color-focus); border-color: var(--xy-theme-focus-border); } .vue-flow__node.selectable:focus:active { box-shadow: var(--xy-node-boxshadow-default); } .vue-flow__node.selectable:hover, .vue-flow__node.draggable:hover { border-color: var(--xy-theme-hover); } .vue-flow__node.selectable.selected { border-color: var(--xy-theme-selected); box-shadow: var(--xy-node-boxshadow-default); } .vue-flow__node-group { background-color: light-dark(rgba(207, 182, 255, 0.4), rgba(123, 107, 148, 0.22)); border-color: light-dark(#9e86ed, #7b6b94); } .vue-flow__edge.selectable:hover .vue-flow__edge-path, .vue-flow__edge.selectable.selected .vue-flow__edge-path { stroke: var(--xy-theme-edge-hover); } .vue-flow__handle { background-color: var(--xy-handle-background-color-default); } .vue-flow__handle.connectionindicator:hover { pointer-events: all; border-color: var(--xy-theme-edge-hover); background-color: var(--xy-handle-background-color-default); } .vue-flow__handle.connectionindicator:focus, .vue-flow__handle.connectingfrom, .vue-flow__handle.connectingto { border-color: var(--xy-theme-edge-hover); } .vue-flow__node-resizer { border-radius: 0; border: none; } .vue-flow__resize-control.handle { background-color: var(--xy-theme-resize-handle-bg); border-color: #9e86ed; border-radius: 0; width: 5px; height: 5px; } /* Custom Example CSS - This CSS is to improve the example experience. You can remove it if you want to use the default styles. New Theme Classes: .xy-theme__button - Styles for buttons. .xy-theme__input - Styles for text inputs. .xy-theme__checkbox - Styles for checkboxes. .xy-theme__select - Styles for dropdown selects. .xy-theme__label - Styles for labels. Use these classes to apply consistent theming across your components. */ .xy-theme__button-group { display: flex; align-items: center; .xy-theme__button:first-child { border-radius: 100px 0 0 100px; } .xy-theme__button:last-child { border-radius: 0 100px 100px 0; margin: 0; } } /* Custom Button Styling */ .xy-theme__button { display: inline-flex; align-items: center; justify-content: center; height: 2.5rem; padding: 0 1rem; border-radius: 100px; border: 1px solid var(--color-primary); background-color: var(--color-background); color: var(--color-primary); transition: background-color 0.2s ease, border-color 0.2s ease; box-shadow: var(--xy-node-boxshadow-default); cursor: pointer; } .xy-theme__button.active { background-color: var(--color-primary); color: white; border-color: var(--color-primary); } .xy-theme__button.active:hover, .xy-theme__button.active:active { background-color: var(--color-primary); opacity: 0.9; } .xy-theme__button:hover { background-color: var(--xy-controls-button-background-color-hover-default); } .xy-theme__button:active { background-color: var(--color-hover-bg); } .xy-theme__button:disabled { color: var(--color-disabled); opacity: 0.8; cursor: not-allowed; border: 1px solid var(--color-disabled); } .xy-theme__button > span { margin-right: 0.2rem; } /* Add gap between adjacent buttons */ .xy-theme__button + .xy-theme__button { margin-left: 0.3rem; } /* Example Input Styling */ .xy-theme__input { padding: 0.5rem 0.75rem; border: 1px solid var(--color-primary); border-radius: 7px; background-color: var(--color-background); transition: background-color 0.2s ease, border-color 0.2s ease; font-size: 1rem; color: var(--xy-theme-panel-text); } .xy-theme__input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.3); } /* Specific Checkbox Styling */ .xy-theme__checkbox { appearance: none; -webkit-appearance: none; width: 1.25rem; height: 1.25rem; border-radius: 7px; border: 2px solid var(--color-primary); background-color: var(--color-background); transition: background-color 0.2s ease, border-color 0.2s ease; cursor: pointer; display: inline-block; vertical-align: middle; margin-right: 0.5rem; } .xy-theme__checkbox:checked { background-color: var(--color-primary); border-color: var(--color-primary); } .xy-theme__checkbox:focus { outline: none; box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.3); } /* Dropdown Styling */ .xy-theme__select { padding: 0.5rem 0.75rem; border: 1px solid var(--color-primary); border-radius: 50px; background-color: var(--color-background); transition: background-color 0.2s ease, border-color 0.2s ease; font-size: 1rem; color: var(--xy-theme-panel-text); margin-right: 0.5rem; box-shadow: var(--xy-node-boxshadow-default); } .xy-theme__select:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.3); } .xy-theme__label { margin-top: 10px; margin-bottom: 3px; display: inline-block; color: var(--xy-theme-panel-text); }
Last updated on