Skip to main content
dublove
Legend
May 15, 2026
Answered

Script Implementation for Aligning Objects to Guides: Align to the Nearest Guide to the Left or Up.

  • May 15, 2026
  • 4 replies
  • 74 views

I’ve always wanted to implement quick alignment of objects to guides.
But since InDesign doesn’t allow selecting both an object and a guide at the same time, it seems impossible to achieve.

Today I just came up with a new approach: have the object align to the nearest guide.
There are too many possible alignment directions, so it’s unnecessary. We only need to align the selected object to the nearest guide to the left or right.

 

This requires two separate scripts: one for left alignment and one for top alignment.

Consider only the top and left margins.
Take top alignment as an example:
You can define what constitutes “nearest” by setting a value yourself. For example, the detection range could be set to ±8mm; objects beyond 8mm will not be affected. If necessary, manually drag them within 8mm.

(Including the guide lines on the Masterpage.)

You might be able to align it even in complex situations by pressing the button repeatedly.

 

    Correct answer Eugene Tyson

    I’m just curious why you need so many scripts? Genuinely curious. 

    ---------------------------------------------------------------------------------------------------------

    Pretty sure you asked for something like this last year - to align to the bleeds?

    Looks like there’s a UserVoice already

    https://indesign.uservoice.com/forums/601021-adobe-indesign-feature-requests/suggestions/50073765-add-align-to-guides-option-in-align-panel

    Can it be done - yes.

    In testing I find it quite strange to have lots of guides drawn arbitrarily around the page - seems like a less efficient way to work. 

    Typically I’d align to Key Object. Then drag to the guide using smart guides, can be sped up with a few key commands.

    And you can do the same to more objects by using the Object>Transform Again or Sequence Individually (i have the indvidual setup as a keyboard shortcut on my other computer - but basically move one or transform one object, then use sequence indvidually on multilpe objects to do the same transformation.

     

    ====================

    Scripting I can’t find an align to guide 

    So I guess you have to read the guide position first

     

    First I tried this and got the alert

    #target "InDesign"

    var guides = app.activeWindow.activePage.guides;
    var msg = "";

    for (var i = 0; i < guides.length; i++) {
    msg += "Guide " + i + "\n";
    msg += "Orientation: " + guides[i].orientation + "\n";
    msg += "Location: " + guides[i].location + "\n\n";
    }

    alert(msg || "No guides on active page.");

     

    Then I tried collecting them with this part 

     

    function collectCandidateGuides(item, orientation) {
    var guides = [];
    var page = getParentPage(item);
    var spread = page ? page.parent : getActiveSpread();

    if (page) {
    addGuides(guides, page.guides, orientation);
    }

    if (spread) {
    addGuides(guides, spread.guides, orientation);
    }

    return guides;
    }

    addGuides() is the part that actually reads each guide’s position:

    out.push(Number(guide.location));

    So for a vertical guide, guide.location is its X position. For a horizontal guide, guide.location is its Y position.

    Then findNearestGuide() compares the selected object edge to every guide position and picks the closest one:

    distance = Math.abs(guides[i] - edge);

    The object edge comes from visibleBounds:

    bounds = item.visibleBounds; // [top, left, bottom, right]

    So:

    left edge = bounds[1] right edge = bounds[3] top edge = bounds[0] bottom edge = bounds[2]

    Finally, alignItemToNearestGuide() calculates how far the object needs to move:

    deltaX = guide - edge; // for left/right alignment deltaY = guide - edge; // for top/bottom alignment

    And moves the object by that amount:

    item.move(undefined, [deltaX, deltaY]);

    So in plain English: it reads all matching guide positions, finds the guide closest to the chosen object edge, subtracts the current edge position from the guide position, then moves the object by exactly that difference.


    Full test script with a rough UI

    I suspect there’s more to your query - and this won’t do what you want out of the box - but it’s just a proof of concept. 

    #target "InDesign"

    (function () {
    var SCRIPT_NAME = "Align Selected Objects to Nearest Guide";

    if (app.documents.length === 0) {
    alert("Open a document first.", SCRIPT_NAME);
    return;
    }

    if (app.selection.length === 0) {
    alert("Select one or more page items first.", SCRIPT_NAME);
    return;
    }

    var side = showDialog(SCRIPT_NAME);

    if (!side) {
    return;
    }

    app.doScript(
    function () {
    alignSelectionToNearestGuide(side);
    },
    ScriptLanguage.JAVASCRIPT,
    undefined,
    UndoModes.ENTIRE_SCRIPT,
    SCRIPT_NAME
    );
    }());

    function showDialog(title) {
    var dlg = new Window("dialog", title);
    dlg.orientation = "column";
    dlg.alignChildren = "fill";

    var panel = dlg.add("panel", undefined, "Align selected object edge to nearest guide");
    panel.orientation = "column";
    panel.alignChildren = "left";
    panel.margins = 14;

    var left = panel.add("radiobutton", undefined, "Left edge to nearest vertical guide");
    var right = panel.add("radiobutton", undefined, "Right edge to nearest vertical guide");
    var top = panel.add("radiobutton", undefined, "Top edge to nearest horizontal guide");
    var bottom = panel.add("radiobutton", undefined, "Bottom edge to nearest horizontal guide");
    left.value = true;

    var buttons = dlg.add("group");
    buttons.alignment = "right";
    buttons.add("button", undefined, "Cancel", { name: "cancel" });
    buttons.add("button", undefined, "OK", { name: "ok" });

    if (dlg.show() !== 1) {
    return null;
    }

    if (right.value) {
    return "right";
    }

    if (top.value) {
    return "top";
    }

    if (bottom.value) {
    return "bottom";
    }

    return "left";
    }

    function alignSelectionToNearestGuide(side) {
    var selection = app.selection;
    var aligned = 0;
    var skipped = [];
    var i;

    for (i = 0; i < selection.length; i++) {
    if (!canAlign(selection[i])) {
    skipped.push(getItemName(selection[i]));
    continue;
    }

    if (alignItemToNearestGuide(selection[i], side)) {
    aligned++;
    } else {
    skipped.push(getItemName(selection[i]));
    }
    }

    if (aligned === 0) {
    alert("No selected page items could be aligned. Check that the relevant guides exist on the page or spread.", "Align Selected Objects to Nearest Guide");
    } else if (skipped.length > 0) {
    alert("Aligned " + aligned + " item(s).\n\nSkipped " + skipped.length + " item(s) with no matching guide or no movable bounds.", "Align Selected Objects to Nearest Guide");
    }
    }

    function canAlign(item) {
    try {
    item.visibleBounds;
    return item && item.isValid && typeof item.move === "function";
    } catch (e) {
    return false;
    }
    }

    function alignItemToNearestGuide(item, side) {
    var bounds;
    var edge;
    var orientation;
    var guide;
    var deltaX = 0;
    var deltaY = 0;

    try {
    bounds = item.visibleBounds; // [top, left, bottom, right]
    } catch (e) {
    return false;
    }

    if (side === "left") {
    edge = bounds[1];
    orientation = "vertical";
    } else if (side === "right") {
    edge = bounds[3];
    orientation = "vertical";
    } else if (side === "top") {
    edge = bounds[0];
    orientation = "horizontal";
    } else {
    edge = bounds[2];
    orientation = "horizontal";
    }

    guide = findNearestGuide(item, orientation, edge);

    if (guide === null) {
    return false;
    }

    if (orientation === "vertical") {
    deltaX = guide - edge;
    } else {
    deltaY = guide - edge;
    }

    try {
    item.move(undefined, [deltaX, deltaY]);
    } catch (e) {
    return false;
    }

    return true;
    }

    function findNearestGuide(item, orientation, edge) {
    var guides = collectCandidateGuides(item, orientation);
    var nearest = null;
    var nearestDistance = Number.MAX_VALUE;
    var i;
    var distance;

    for (i = 0; i < guides.length; i++) {
    distance = Math.abs(guides[i] - edge);

    if (distance < nearestDistance) {
    nearestDistance = distance;
    nearest = guides[i];
    }
    }

    return nearest;
    }

    function collectCandidateGuides(item, orientation) {
    var guides = [];
    var page = getParentPage(item);
    var spread = page ? page.parent : getActiveSpread();

    if (page) {
    addGuides(guides, page.guides, orientation);
    }

    if (spread) {
    addGuides(guides, spread.guides, orientation);
    }

    return guides;
    }

    function addGuides(out, guides, orientation) {
    var i;
    var guide;

    for (i = 0; i < guides.length; i++) {
    guide = guides[i];

    if (guideMatchesOrientation(guide, orientation)) {
    out.push(Number(guide.location));
    }
    }
    }

    function guideMatchesOrientation(guide, orientation) {
    var value;

    try {
    value = String(guide.orientation).toLowerCase();
    } catch (e) {
    return false;
    }

    if (orientation === "vertical") {
    return value.indexOf("vertical") !== -1;
    }

    return value.indexOf("horizontal") !== -1;
    }

    function getParentPage(item) {
    try {
    if (item.parentPage && item.parentPage.isValid) {
    return item.parentPage;
    }
    } catch (e) {}

    try {
    if (item.parent && item.parent.parentPage && item.parent.parentPage.isValid) {
    return item.parent.parentPage;
    }
    } catch (e2) {}

    return null;
    }

    function getActiveSpread() {
    try {
    if (app.activeWindow && app.activeWindow.activeSpread && app.activeWindow.activeSpread.isValid) {
    return app.activeWindow.activeSpread;
    }
    } catch (e) {}

    return null;
    }

    function getItemName(item) {
    try {
    if (item.name) {
    return item.name;
    }
    } catch (e) {}

    try {
    return item.constructor.name;
    } catch (e2) {
    return "Item";
    }
    }

    It’s probably far simpler than I’m making it out to be.

    There’s already scripts to draw from in the ones supplied with InDesign

     

    And more importantly this one

     

    4 replies

    Participating Frequently
    May 16, 2026

    Eugene is quite correct of course, it is neccessary to include any guides that are inherited from a parent page. It’s worse that that in fact because you would also need to check for  guides on a parent page inherited from another parent page and so on. (My script avoids that because it infers the horizontal grid from the spacing of the baseline grid.)

    As for guides on parent spread but outside the page area —it seems they are not inherited and nor is anything else entirely outside the page area. Which I suppose makes sense.

    dublove
    dubloveAuthor
    Legend
    May 16, 2026

    @Eugene Tyson 

    The guide lines are on the masterPage(home page), but the objects aren't recognized on the work page?

    Community Expert
    May 16, 2026

    If the guides are on the parent page then

    page.appliedMaster

     

    include this directly after addGuides():

    function addAppliedMasterGuides(out, page, orientation) {
    var master;
    var masterPages;
    var i;

    try {
    master = page.appliedMaster;
    if (!master || !master.isValid) {
    return;
    }
    } catch (e) {
    return;
    }

    try {
    addGuides(out, master.guides, orientation);
    } catch (e2) {}

    try {
    masterPages = master.pages.everyItem().getElements();
    for (i = 0; i < masterPages.length; i++) {
    addGuides(out, masterPages[i].guides, orientation);
    }
    } catch (e3) {}
    }

    So now they’re alongside the normal page/spread guides.

     

    Inside collectCandidateTargets(), change this part
     

    if (targetMode === "guides" || targetMode === "both") {
        if (page) {
            addGuides(targets, page.guides, orientation);
        }

        if (spread) {
            addGuides(targets, spread.guides, orientation);
        }
    }

     

    to

    if (targetMode === "guides" || targetMode === "both") {
    if (page) {
    addGuides(targets, page.guides, orientation);
    }

    if (spread) {
    addGuides(targets, spread.guides, orientation);
    }

    if (page) {
    addAppliedMasterGuides(targets, page, orientation);
    }
    }

     

     

     

    dublove
    dubloveAuthor
    Legend
    May 16, 2026

    @Eugene Tyson 

    Thank you.

    I've successfully made the changes (both the new and old versions).

    I've found another issue:

    When the guide is on the masterpage and the object is outside the page,
    it cannot be recognized.

     

     

    Participating Frequently
    May 16, 2026

    I've done somethng similar for newspaper layouts with quite detailed grids of guidelines (horizontal guides that relate to the document's baseline grid but shifted by the cap height of body text to ensure alignment of text frames and pictures).


    It works by getting the bounds of the object-to-be-aligned and then a list of all guides on the page and doing a search for the nearest guide in the list for all four sides of the object-to-be-aligned in turn and adjusting the bounds to suit. 


    It has a couple of special cases to raise the bottom of pictures slightly to allow for captions and for column guides and also to ensure the right side of a frame goes to the left side of a column gutter and vice versa.


    It sounds long-winded but on any fairly modern machine it's done in a blink.


    It's all in AppleScript — but of course the same logic could be applied in JavaScript. 


     

    use AppleScript version "2.4" -- Yosemite (10.10) or later
    use scripting additions
    ------------------------------------------------------------------
    # VERSION SAVED @ Tuesday 15 April 2025 at 11:43:57
    ------------------------------------------------------------------
    property ColumnRuleGuidesList : missing value -- need to generate this
    property LeftSideList : missing value
    property RightSideList : missing value
    property PageHeight : missing value
    property PageWidth : missing value
    property HorizontalGuides : missing value
    property ActivePage : missing value
    property TopMargin : missing value
    property BottomMargin : missing value
    property TypeLineFeed : missing value
    property BaselineStart : missing value
    property TheDoc : missing value
    property TheSelection : missing value
    property PagesOfSpread : missing value
    property LeftPageLeftSide : {}
    property LeftPageRightSide : {}
    property RightPageLeftSide : {}
    property RightPageRightSide : {}
    property PullBackPic : false
    -- display dialog "message" buttons {"Cancel", "OK"} default button "OK"
    CheckForDocument()
    SetProperties()
    LoadColumnPositions()
    ListHorizontalGuides()
    tell application id "com.adobe.InDesign"
    activate
    repeat with s from 1 to count of items of TheSelection
    set NextItem to item s of TheSelection
    set NextItemElementLabel to "" -- («class ElLa» of nextItem)
    if class of NextItem is not graphic line then
    if {"PF Picture Frame"} contains NextItemElementLabel then
    set PullBackPic to true
    else
    set PullBackPic to false
    end if
    end if
    -- How to detect a column rule????
    if (side of parent page of NextItem) is left hand then
    set y1 to (GNV((item 1 of (geometric bounds of NextItem)), HorizontalGuides) of me)
    set x1 to (GNV((item 2 of (geometric bounds of NextItem)), LeftPageLeftSide) of me)
    set y2 to (GNV((item 3 of (geometric bounds of NextItem)), HorizontalGuides) of me)
    set x2 to (GNV((item 4 of (geometric bounds of NextItem)), LeftPageRightSide) of me)
    --set geometric bounds of nextitem to {y1, x1, y2, x2}
    end if
    if (side of parent page of NextItem) is right hand then
    set y1 to (GNV((item 1 of (geometric bounds of NextItem)), HorizontalGuides) of me)
    set x1 to (GNV((item 2 of (geometric bounds of NextItem)), RightPageLeftSide) of me)
    set y2 to (GNV((item 3 of (geometric bounds of NextItem)), HorizontalGuides) of me)
    set x2 to (GNV((item 4 of (geometric bounds of NextItem)), RightPageRightSide) of me)
    end if
    set SkipMe to false
    if PullBackPic is true then
    set y2 to y2 - (TypeLineFeed - BaselineStart)
    end if
    if class of NextItem is graphic line then
    if stroke weight of NextItem is 0.25 then
    if y2 - y1 > 20 then
    -- Is it really a column rule? Is there any other test?
    set x1 to x1 + 6
    set x2 to x2 + 6
    set y2 to y2 - (TypeLineFeed - BaselineStart)
    else
    --set SkipMe to true
    end if
    end if
    end if
    if SkipMe is false then
    if class of NextItem is in {rectangle, text frame, graphic line} then
    set geometric bounds of NextItem to {y1, x1, y2, x2}
    end if
    end if
    end repeat
    end tell
    ------------------------------------------------------------------------------------------------------------
    # Check there's a document and something selected
    ------------------------------------------------------------------------------------------------------------
    on CheckForDocument()
    tell application id "com.adobe.InDesign"
    activate
    if (count of document) = 0 then
    display dialog "There is no document open" with title "No Document" buttons {"Cancel"} default button "Cancel"
    end if
    tell document 1
    set TheSelection to selection
    end tell
    if TheSelection is {} then
    display dialog "There is nothing selected" with title "No Selection" buttons {"Cancel"} default button "Cancel"
    end if
    end tell
    end CheckForDocument
    ------------------------------------------------------------------------------------------------------------
    # Make sure some prefs are as we need them to be
    ------------------------------------------------------------------------------------------------------------
    on SetProperties()
    tell application id "com.adobe.InDesign"
    set TheDoc to document 1
    tell TheDoc
    set ruler origin of view preferences to page origin
    set zero point to {0, 0}
    set horizontal measurement units of view preferences to points
    set vertical measurement units of view preferences to points
    set TypeLineFeed to baseline division of grid preferences
    set BaselineStart to baseline start of grid preferences
    set TheSelection to selection
    set PageWidth to page width of document preferences
    set PageHeight to page height of document preferences
    set TopMargin to (top of (margin preferences))
    set BottomMargin to (bottom of (margin preferences))
    end tell
    set TheActiveSpread to parent of parent page of (item 1 of TheSelection)
    set PagesOfSpread to every page of TheActiveSpread
    end tell
    end SetProperties
    ------------------------------------------------------------------------------------------------------------
    # Find Columns
    ------------------------------------------------------------------------------------------------------------
    on LoadColumnPositions()
    tell application id "com.adobe.InDesign"
    repeat with p from 1 to count of items of PagesOfSpread
    tell (item p of PagesOfSpread)
    set WhatSide to side
    tell margin preferences
    set InsideMargin to left
    set OutsideMargin to right
    set ColumnPositions to columns positions
    end tell
    if side is left hand then
    set ColumnStartPoint to OutsideMargin
    set FurthestLeftToDraw to OutsideMargin
    set FurthestRightToDraw to (PageWidth - InsideMargin)
    repeat with y from 1 to count of items of ColumnPositions by 2
    set LeftPageLeftSide to LeftPageLeftSide & ((item y of ColumnPositions) + ColumnStartPoint)
    set LeftPageRightSide to LeftPageRightSide & ((item (y + 1) of ColumnPositions) + ColumnStartPoint)
    end repeat
    end if
    if side is right hand then
    set ColumnStartPoint to InsideMargin
    set FurthestLeftToDraw to InsideMargin
    set FurthestRightToDraw to (PageWidth - OutsideMargin)
    repeat with y from 1 to count of items of ColumnPositions by 2
    set RightPageLeftSide to RightPageLeftSide & ((item y of ColumnPositions) + ColumnStartPoint)
    set RightPageRightSide to RightPageRightSide & ((item (y + 1) of ColumnPositions) + ColumnStartPoint)
    end repeat
    end if

    end tell
    end repeat
    end tell
    end LoadColumnPositions
    ------------------------------------------------------------------------------------------------------------
    # List Horizontal Guides (based on the baseline grid but shifted to bring cap height onto the object grid)
    ------------------------------------------------------------------------------------------------------------
    on ListHorizontalGuides()
    set p to TopMargin
    set HorizontalGuides to {}
    repeat while p < ((PageHeight - BottomMargin) + 1)
    set HorizontalGuides to HorizontalGuides & p
    set p to (p + TypeLineFeed)
    end repeat
    end ListHorizontalGuides
    ------------------------------------------------------------------------------------------------------------
    # Get Nearest Value from a list
    ------------------------------------------------------------------------------------------------------------
    on GNV(theValue, theList) -- GetNearestValue
    set TestCase to 100000
    set HoldValue to 0
    repeat with v from 1 to (count of items of theList)
    set TheGap to (theValue - (item v of theList))
    if TheGap < 0 then
    set TheGap to (TheGap * -1)
    end if
    if TheGap < TestCase then
    set TestCase to TheGap
    set HoldValue to (item v of theList)
    end if
    end repeat
    return HoldValue
    end GNV

     

    Eugene TysonCommunity ExpertCorrect answer
    Community Expert
    May 15, 2026

    I’m just curious why you need so many scripts? Genuinely curious. 

    ---------------------------------------------------------------------------------------------------------

    Pretty sure you asked for something like this last year - to align to the bleeds?

    Looks like there’s a UserVoice already

    https://indesign.uservoice.com/forums/601021-adobe-indesign-feature-requests/suggestions/50073765-add-align-to-guides-option-in-align-panel

    Can it be done - yes.

    In testing I find it quite strange to have lots of guides drawn arbitrarily around the page - seems like a less efficient way to work. 

    Typically I’d align to Key Object. Then drag to the guide using smart guides, can be sped up with a few key commands.

    And you can do the same to more objects by using the Object>Transform Again or Sequence Individually (i have the indvidual setup as a keyboard shortcut on my other computer - but basically move one or transform one object, then use sequence indvidually on multilpe objects to do the same transformation.

     

    ====================

    Scripting I can’t find an align to guide 

    So I guess you have to read the guide position first

     

    First I tried this and got the alert

    #target "InDesign"

    var guides = app.activeWindow.activePage.guides;
    var msg = "";

    for (var i = 0; i < guides.length; i++) {
    msg += "Guide " + i + "\n";
    msg += "Orientation: " + guides[i].orientation + "\n";
    msg += "Location: " + guides[i].location + "\n\n";
    }

    alert(msg || "No guides on active page.");

     

    Then I tried collecting them with this part 

     

    function collectCandidateGuides(item, orientation) {
    var guides = [];
    var page = getParentPage(item);
    var spread = page ? page.parent : getActiveSpread();

    if (page) {
    addGuides(guides, page.guides, orientation);
    }

    if (spread) {
    addGuides(guides, spread.guides, orientation);
    }

    return guides;
    }

    addGuides() is the part that actually reads each guide’s position:

    out.push(Number(guide.location));

    So for a vertical guide, guide.location is its X position. For a horizontal guide, guide.location is its Y position.

    Then findNearestGuide() compares the selected object edge to every guide position and picks the closest one:

    distance = Math.abs(guides[i] - edge);

    The object edge comes from visibleBounds:

    bounds = item.visibleBounds; // [top, left, bottom, right]

    So:

    left edge = bounds[1] right edge = bounds[3] top edge = bounds[0] bottom edge = bounds[2]

    Finally, alignItemToNearestGuide() calculates how far the object needs to move:

    deltaX = guide - edge; // for left/right alignment deltaY = guide - edge; // for top/bottom alignment

    And moves the object by that amount:

    item.move(undefined, [deltaX, deltaY]);

    So in plain English: it reads all matching guide positions, finds the guide closest to the chosen object edge, subtracts the current edge position from the guide position, then moves the object by exactly that difference.


    Full test script with a rough UI

    I suspect there’s more to your query - and this won’t do what you want out of the box - but it’s just a proof of concept. 

    #target "InDesign"

    (function () {
    var SCRIPT_NAME = "Align Selected Objects to Nearest Guide";

    if (app.documents.length === 0) {
    alert("Open a document first.", SCRIPT_NAME);
    return;
    }

    if (app.selection.length === 0) {
    alert("Select one or more page items first.", SCRIPT_NAME);
    return;
    }

    var side = showDialog(SCRIPT_NAME);

    if (!side) {
    return;
    }

    app.doScript(
    function () {
    alignSelectionToNearestGuide(side);
    },
    ScriptLanguage.JAVASCRIPT,
    undefined,
    UndoModes.ENTIRE_SCRIPT,
    SCRIPT_NAME
    );
    }());

    function showDialog(title) {
    var dlg = new Window("dialog", title);
    dlg.orientation = "column";
    dlg.alignChildren = "fill";

    var panel = dlg.add("panel", undefined, "Align selected object edge to nearest guide");
    panel.orientation = "column";
    panel.alignChildren = "left";
    panel.margins = 14;

    var left = panel.add("radiobutton", undefined, "Left edge to nearest vertical guide");
    var right = panel.add("radiobutton", undefined, "Right edge to nearest vertical guide");
    var top = panel.add("radiobutton", undefined, "Top edge to nearest horizontal guide");
    var bottom = panel.add("radiobutton", undefined, "Bottom edge to nearest horizontal guide");
    left.value = true;

    var buttons = dlg.add("group");
    buttons.alignment = "right";
    buttons.add("button", undefined, "Cancel", { name: "cancel" });
    buttons.add("button", undefined, "OK", { name: "ok" });

    if (dlg.show() !== 1) {
    return null;
    }

    if (right.value) {
    return "right";
    }

    if (top.value) {
    return "top";
    }

    if (bottom.value) {
    return "bottom";
    }

    return "left";
    }

    function alignSelectionToNearestGuide(side) {
    var selection = app.selection;
    var aligned = 0;
    var skipped = [];
    var i;

    for (i = 0; i < selection.length; i++) {
    if (!canAlign(selection[i])) {
    skipped.push(getItemName(selection[i]));
    continue;
    }

    if (alignItemToNearestGuide(selection[i], side)) {
    aligned++;
    } else {
    skipped.push(getItemName(selection[i]));
    }
    }

    if (aligned === 0) {
    alert("No selected page items could be aligned. Check that the relevant guides exist on the page or spread.", "Align Selected Objects to Nearest Guide");
    } else if (skipped.length > 0) {
    alert("Aligned " + aligned + " item(s).\n\nSkipped " + skipped.length + " item(s) with no matching guide or no movable bounds.", "Align Selected Objects to Nearest Guide");
    }
    }

    function canAlign(item) {
    try {
    item.visibleBounds;
    return item && item.isValid && typeof item.move === "function";
    } catch (e) {
    return false;
    }
    }

    function alignItemToNearestGuide(item, side) {
    var bounds;
    var edge;
    var orientation;
    var guide;
    var deltaX = 0;
    var deltaY = 0;

    try {
    bounds = item.visibleBounds; // [top, left, bottom, right]
    } catch (e) {
    return false;
    }

    if (side === "left") {
    edge = bounds[1];
    orientation = "vertical";
    } else if (side === "right") {
    edge = bounds[3];
    orientation = "vertical";
    } else if (side === "top") {
    edge = bounds[0];
    orientation = "horizontal";
    } else {
    edge = bounds[2];
    orientation = "horizontal";
    }

    guide = findNearestGuide(item, orientation, edge);

    if (guide === null) {
    return false;
    }

    if (orientation === "vertical") {
    deltaX = guide - edge;
    } else {
    deltaY = guide - edge;
    }

    try {
    item.move(undefined, [deltaX, deltaY]);
    } catch (e) {
    return false;
    }

    return true;
    }

    function findNearestGuide(item, orientation, edge) {
    var guides = collectCandidateGuides(item, orientation);
    var nearest = null;
    var nearestDistance = Number.MAX_VALUE;
    var i;
    var distance;

    for (i = 0; i < guides.length; i++) {
    distance = Math.abs(guides[i] - edge);

    if (distance < nearestDistance) {
    nearestDistance = distance;
    nearest = guides[i];
    }
    }

    return nearest;
    }

    function collectCandidateGuides(item, orientation) {
    var guides = [];
    var page = getParentPage(item);
    var spread = page ? page.parent : getActiveSpread();

    if (page) {
    addGuides(guides, page.guides, orientation);
    }

    if (spread) {
    addGuides(guides, spread.guides, orientation);
    }

    return guides;
    }

    function addGuides(out, guides, orientation) {
    var i;
    var guide;

    for (i = 0; i < guides.length; i++) {
    guide = guides[i];

    if (guideMatchesOrientation(guide, orientation)) {
    out.push(Number(guide.location));
    }
    }
    }

    function guideMatchesOrientation(guide, orientation) {
    var value;

    try {
    value = String(guide.orientation).toLowerCase();
    } catch (e) {
    return false;
    }

    if (orientation === "vertical") {
    return value.indexOf("vertical") !== -1;
    }

    return value.indexOf("horizontal") !== -1;
    }

    function getParentPage(item) {
    try {
    if (item.parentPage && item.parentPage.isValid) {
    return item.parentPage;
    }
    } catch (e) {}

    try {
    if (item.parent && item.parent.parentPage && item.parent.parentPage.isValid) {
    return item.parent.parentPage;
    }
    } catch (e2) {}

    return null;
    }

    function getActiveSpread() {
    try {
    if (app.activeWindow && app.activeWindow.activeSpread && app.activeWindow.activeSpread.isValid) {
    return app.activeWindow.activeSpread;
    }
    } catch (e) {}

    return null;
    }

    function getItemName(item) {
    try {
    if (item.name) {
    return item.name;
    }
    } catch (e) {}

    try {
    return item.constructor.name;
    } catch (e2) {
    return "Item";
    }
    }

    It’s probably far simpler than I’m making it out to be.

    There’s already scripts to draw from in the ones supplied with InDesign

     

    And more importantly this one

     

    dublove
    dubloveAuthor
    Legend
    May 16, 2026

    @Eugene Tyson 

    Your model is good.

    Thank you very much,


    My personal suggestion is to divide it into 4 scripts, and if necessary, assign 4 shortcut keys instead of a dialog box, which significantly reduces speed and user experience.

    I directly commented out the dialog box.

    Also, “#target "InDesign” seems unnecessary.

    Could it slow down the code? Once, I was running in ID2024 and it was strange that ID2026 was opened.

    //#target "InDesign"
    . . .
    var side = 'top';
    //var side = showDialog(SCRIPT_NAME);
    . . .

    Oh, I noticed a digression:

    Can I @ Adobe Forum Builder?
    Why not set the default code to JS?
    I always want to be lazy enough to skip every small step.