how to create a floating menu that accepts dropped items

am trying to create a floating menu window/box that accepts a dropped item (ex. a link), then run a script with that item.

i tried with the notch example but i dont know what am doing exactly and how to get the drop to work correctly.

I have just updated the drop behavior today. Previously only dropping files was possible, now all kind of things can be dropped. You need at least BTT 5.355 alpha. I still need to document it however.

Everything dropped onto an item can be retrieved via get_menu_item_value either from Apple Script or (better) BTT's Java Script

The dropped items are available in all representations provided by the system in a JSON object. For example:

{
  "public.html": [{
    "uti": "public.html",
    "type": "text",
    "value": "<b>Hello</b>",
    "timestamp": "2025-05-04T21:00:00Z"
  }],
  "public.file-url": [{
    "uti": "public.file-url",
    "type": "file",
    "value": "/Users/you/Desktop/file.txt",
    "timestamp": "2025-05-04T21:00:00Z"
  }]
}

Here is a example preset:
drop-example.bttpreset (19.2 KB)

async function getDrops() {
    let dropJSONString = await get_menu_item_value( {itemUUID: "76DBA7CD-B472-4E3C-BC6B-8AA1CA922BE9"});
    // parse the saved string into a Java Script object:
    let itemVal = JSON.parse(dropJSONString);

     // setting it on the text area item, so we can view the dropped content
     await set_menu_item_value( {itemUUID: "50C1D052-2B39-4D24-806B-39273974C0C8", 'value': JSON.stringify(itemVal, null, 2)});

     // example of how you would access a dropped url:
    return itemVal["public.url"][0]["value"];
}

2 Likes

Very interested in this - to drag items from the desktop to a nested NAS directory through a floating menu.

Are there plug ins, or a spot to share mods and use/try/learn from other creators?

I am not a coder..is this cut and paste to replicate the functionality? Does BTT have working examples to use?

if you can post the directory path I can create the script you‘d need to use

Oh?! That would be great! The target directory (ies) are on a Synology NAS. Seems like url schema vary and not sure which version. I will post when I am back at the computer to grab the URL (and I can make the versions for other target directories.

Goal: Move file from desktop to target directory (meaning original item goes to the trash as part of the workflow.)

URL created by opening terminal on the Mac and dragging the target directory to prompt.

Has an image to share but not seeing a way to include an image

/Volumes/Source\ Prefs/2025/Transactions \ 2025

here is an example:
dropexample2.bttpreset (18.3 KB)

It uses this script:

async function moveDrops() {
    // change target folder here:
    let targetFolder = "/Volumes/Source Prefs/2025/Transactions 2025/";

    let dropJSONString = await get_menu_item_value( {itemUUID: "A2B4AC00-2A9E-4B29-B5BA-1C6D08D04E7D"});
    let itemVal = JSON.parse(dropJSONString);
   	let droppedFiles = itemVal["public.file-url"];
	for (file of droppedFiles) {
		await runShellScript({script: `mv  "${file["value"]}" "${targetFolder}"`});
	}

    return "done"
}

Ok, think I did everything right however the action isn’t moving files. I have action to trigger on drop. The HUD notice flashes on drop (but also flashes on click?) and no file moves to target directory.

Created a version using a local directory for testing purposes. No file being moved.

Not sure what I am doing wrong.
Run Script button shows “SyntaxError: JSON Parde error: Unexpexted identifier “undefined”

are you on the current alpha version of BTT?

I've tried setting this up, but it doesn't work at all for me. :(((

async function moveDrops() {
    function urlToPath(url) {
        return decodeURIComponent(url.replace(/^file:\/\//, ''));
    }

    alert("Drop detected, script running");

    let targetFolder = "/Volumes/Backup1/Test";

    let dropJSONString = await get_menu_item_value({itemUUID: "A2B4AC00-2A9E-4B29-B5BA-1C6D08D04E7D"});
    if (!dropJSONString) {
        alert("No drop data received");
        return "No drop data";
    }

    let itemVal;
    try {
        itemVal = JSON.parse(dropJSONString);
    } catch(e) {
        alert("JSON parse error: " + e.message);
        return "JSON parse error: " + e.message;
    }

    alert("Keys in drop data: " + Object.keys(itemVal).join(", "));

    // Try these keys one by one
    let droppedFiles = itemVal["com.apple.pasteboard.promised-file-url"];
    if (!droppedFiles || droppedFiles.length === 0) {
        droppedFiles = itemVal["public.url"];
    }
    if (!droppedFiles || droppedFiles.length === 0) {
        alert("No files found in expected keys");
        return "No files found";
    }

    for (const file of droppedFiles) {
        const filePath = urlToPath(file["value"]);
        let cmd = `echo mv "${filePath}" "${targetFolder}" >> ~/Desktop/btt-move-log.txt`;
        await runShellScript({script: cmd});
    }

    alert("Move commands logged to ~/Desktop/btt-move-log.txt");
    return JSON.stringify(droppedFiles);
}

Version 5.377

try to add the drop action on an item, not the menu itself, make sure to adapt the uuids

Think that’s what I was doing? Tried a few options. In the below recording, no file moved.
I made a video but not seeing a way to attach or upload (short of finding a third party host and link)

Likely missing something simple. While everything looks like it works (hover state and such - no files are moving also didn’t follow how to adapt uuids