This example uses OpenLayers v10.9.0. The latest is v.
Edit

#### Snap Interaction

draw 17 edit 13 modify 11 vector 86 snap 4

#####

Snapped: false
Draw
Modify

Example of using the snap interaction together with draw and modify interactions.

Example of using the snap interaction together with draw and modify interactions. The snap interaction must be added last, as it needs to be the first to handle the `pointermove` event.

By default, the Snap interaction snaps to edges (`edge: true`) and vertices (`vertex: true`). It can also be configured to snap to intersections between edges, which is done here with the `intersection: true` option.

##### main.js

    import Map from 'ol/Map.js';
    import View from 'ol/View.js';
    import Draw from 'ol/interaction/Draw.js';
    import Modify from 'ol/interaction/Modify.js';
    import Select from 'ol/interaction/Select.js';
    import Snap from 'ol/interaction/Snap.js';
    import TileLayer from 'ol/layer/Tile.js';
    import VectorLayer from 'ol/layer/Vector.js';
    import OSM from 'ol/source/OSM.js';
    import VectorSource from 'ol/source/Vector.js';

    const raster = new TileLayer({
      source: new OSM(),
    });

    const vector = new VectorLayer({
      source: new VectorSource(),
      style: {
        'fill-color': 'rgba(255, 255, 255, 0.2)',
        'stroke-color': '#ffcc33',
        'stroke-width': 2,
        'circle-radius': 7,
        'circle-fill-color': '#ffcc33',
      },
    });

    const map = new Map({
      layers: [raster, vector],
      target: 'map',
      view: new View({
        center: [-11000000, 4600000],
        zoom: 4,
      }),
    });

    const ExampleModify = {
      init: function () {
        this.select = new Select();
        map.addInteraction(this.select);

        this.modify = new Modify({
          features: this.select.getFeatures(),
        });
        map.addInteraction(this.modify);

        this.setEvents();
      },
      setEvents: function () {
        const selectedFeatures = this.select.getFeatures();

        this.select.on('change:active', function () {
          selectedFeatures.forEach(function (each) {
            selectedFeatures.remove(each);
          });
        });
      },
      setActive: function (active) {
        this.select.setActive(active);
        this.modify.setActive(active);
      },
    };
    ExampleModify.init();

    const optionsForm = document.getElementById('options-form');

    const ExampleDraw = {
      init: function () {
        map.addInteraction(this.Point);
        this.Point.setActive(false);
        map.addInteraction(this.LineString);
        this.LineString.setActive(false);
        map.addInteraction(this.Polygon);
        this.Polygon.setActive(false);
        map.addInteraction(this.Circle);
        this.Circle.setActive(false);
      },
      Point: new Draw({
        source: vector.getSource(),
        type: 'Point',
      }),
      LineString: new Draw({
        source: vector.getSource(),
        type: 'LineString',
      }),
      Polygon: new Draw({
        source: vector.getSource(),
        type: 'Polygon',
      }),
      Circle: new Draw({
        source: vector.getSource(),
        type: 'Circle',
      }),
      activeDraw: null,
      setActive: function (active) {
        if (this.activeDraw) {
          this.activeDraw.setActive(false);
          this.activeDraw = null;
        }
        if (active) {
          const type = optionsForm.elements['draw-type'].value;
          this.activeDraw = this[type];
          this.activeDraw.setActive(true);
        }
      },
    };
    ExampleDraw.init();

    /**
     * Let user change the geometry type.
     * @param {Event} e Change event.
     */
    optionsForm.onchange = function (e) {
      const type = e.target.getAttribute('name');
      if (type == 'draw-type') {
        ExampleModify.setActive(false);
        ExampleDraw.setActive(true);
        optionsForm.elements['interaction'].value = 'draw';
      } else if (type == 'interaction') {
        const interactionType = e.target.value;
        if (interactionType == 'modify') {
          ExampleDraw.setActive(false);
          ExampleModify.setActive(true);
        } else if (interactionType == 'draw') {
          ExampleDraw.setActive(true);
          ExampleModify.setActive(false);
        }
      }
    };

    ExampleDraw.setActive(true);
    ExampleModify.setActive(false);

    // The snap interaction must be added after the Modify and Draw interactions
    // in order for its map browser event handlers to be fired first. Its handlers
    // are responsible of doing the snapping.
    const snap = new Snap({
      source: vector.getSource(),
      intersection: true,
    });

    const snappedElement = document.getElementById('snapped');

    snap.on('snap', () => {
      document.getElementById('map').style.cursor = 'grabbing';
      snappedElement.innerHTML = 'Snapped: true';
    });

    snap.on('unsnap', () => {
      document.getElementById('map').style.cursor = 'default';
      snappedElement.innerHTML = 'Snapped: false';
    });

    map.addInteraction(snap);

##### index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Snap Interaction</title>
        <link rel="stylesheet" href="node_modules/ol/ol.css">
        <style>
          .map {
            width: 100%;
            height: 400px;
          }
        </style>
      </head>
      <body>
        <div id="map" class="map"></div>
        <span id="snapped">Snapped: false</span>
        <form id="options-form" autocomplete="off">
          <div class="radio">
            <label>
              <input type="radio" name="interaction" value="draw" id="draw" checked>
              Draw &nbsp;
            </label>
            <select name="draw-type" id="draw-type">
              <option value="Point">Point</option>
              <option value="LineString">LineString</option>
              <option value="Polygon">Polygon</option>
              <option value="Circle">Circle</option>
            </select>
          </div>
          <div class="radio">
            <label>
              <input type="radio" name="interaction" value="modify">
              Modify &nbsp;
            </label>
          </div>
        </form>

        <script type="module" src="main.js"></script>
      </body>
    </html>

##### package.json

    {
      "name": "snap",
      "dependencies": {
        "ol": "10.9.0"
      },
      "devDependencies": {
        "vite": "^3.2.3"
      },
      "scripts": {
        "start": "vite",
        "build": "vite build"
      }
    }