Skip to main content
Inspiring
June 10, 2011
Open for Voting

Photoshop: Record expand/collapse groups in actions

  • June 10, 2011
  • 21 replies
  • 3552 views
I would love the ability to record the "Collapse groups" shortcut John Nack mentioned here: http://blogs.adobe.com/jnack/2011/06/... in my actions.

In my actions I often create lots and lots of folders that I'll need afterwards (workflow actions), which then stay open all the time so I have to collapse them manually.
Therefore it'd be great to be able to record the collapse command to save time and improve the overview over my layers/groups.

21 replies

Stephen Marsh
Community Expert
Community Expert
October 14, 2025
quote

... I think this can be done using scripting. One day when I learn scripting life will be grand

By @Bruce! 

 

If only things were that simple!

 

It's a pet hate of mine that one feature is offered, such as "Collapse all groups", however the opposite and complimentary commands are not offered! There should be "Expand all groups" and "Collapse selected group" and "Expand selected group" for use with Actions and scripting, which can't be recorded via the GUI.

 

https://gist.github.com/MarshySwamp/a39e3e1efee41174b3b92ee68c40fcd8

 

// Collapse ALL layer groups/sets

app.runMenuItem(stringIDToTypeID('collapseAllGroupsEvent'));

 

// Expand ALL layer groups/sets

openAllLayerSets(app.activeDocument);

function openAllLayerSets(parent) {
    // https://forums.adobe.com/message/5764024#5764024
    for (var setIndex = 0; setIndex < parent.layerSets.length; setIndex++) {
        app.activeDocument.activeLayer = parent.layerSets[setIndex].layers[0];
        openAllLayerSets(parent.layerSets[setIndex]);
    }
}

 

// Expand active layer set

if (app.activeDocument.activeLayer.typename == 'LayerSet' && app.activeDocument.activeLayer.layers.length > 0) {
    app.activeDocument.activeLayer = app.activeDocument.activeLayer.layers[0];
}

 

To collapse only the active layer group would seem easy, but it's not, back in 2022 this is the best that I came up with, however, it still wasn't perfect. It's a hack, and there were unexpected consequences which required further hacks etc:

 

/*
Collapse Active Group.jsx
Modified by Stephen Marsh, 17th August 2022
https://gist.github.com/MarshySwamp/a39e3e1efee41174b3b92ee68c40fcd8
https://community.adobe.com/t5/photoshop-ecosystem-discussions/collapse-single-group-of-layers/m-p/13132297
Based on:
https://community.adobe.com/t5/photoshop-ecosystem/expand-collapse-a-group-via-javascript/m-p/7286298
By Vova_p, 16th February 2016
*** KNOWN LIMITATIONS & GOTCHAS ***
This script is a hack to overcome a shortcoming of the original implementation of layer groups/sets:
+ Layers clipped to the group will lose their clipping group property
+ Default layer names such as "Layer 6" may be auto-renamed by Photoshop to "Layer 10" etc.
*/

#target photoshop

if (app.documents.length > 0) {

    function main() {

        if (activeDocument.activeLayer.typename === "LayerSet") {

            // Set the original document
            var origDoc = app.activeDocument;

            // Doc name variable
            var origDocName = activeDocument.name;

            // Store the name of the group
            var groupname = activeDocument.activeLayer.name;

            // Copy the active layer properties to a layer style (opacity, fill, blend mode, blend-if etc)
            var idcopyEffects = stringIDToTypeID("copyEffects");
            executeAction(idcopyEffects, undefined, DialogModes.NO);

            // Toggle the active layer visibility
            toggleLayerVisibility(true);

            // Create the temp doc from active layer group
            newDocFromLayer("_tempDoc");

            // Set the "destination" group variable
            var destinationGroup = activeDocument.activeLayer.name;

            // Dupe the set into a temp group
            activeDocument.activeLayer.duplicate();

            // Set the duped "source" group variable
            var sourceGroup = activeDocument.layers[0].name;

            // Ungroup the group to select all the child elements
            unGroup();

            // Group the selected layers to collapse the group
            groupSelectedLayers();

            // Recall the original group name
            activeDocument.activeLayer.name = groupname;

            // Copy the layer mask with all properties from the temp group
            copyLayerMask();

            // Restore the layer style to the new collapsed group
            pasteEffects(true);

            // Select and remove the temp group
            activeDocument.activeLayer = activeDocument.layers[0];
            activeDocument.activeLayer.remove();

            // Dupe the group back to the original doc
            dupeLayer();

            // Close the temp doc
            activeDocument.close(SaveOptions.DONOTSAVECHANGES);

            // Return to the original document
            app.activeDocument = origDoc;

            // Select the visible backward layer
            selectForwardORBackwardLayer(false, "backwardEnum");

            // Delete the original expanded group
            removeGroup();

            // Select the visible forward layer
            selectForwardORBackwardLayer(false, "forwardEnum");

            // Toggle the original active layer visibility
            toggleLayerVisibility(true);

        } else {
            alert("Only layer groups can be collapsed!");
        }

        /***** Functions *****/

        function dupeLayer() {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var list = new ActionList();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("null"), reference);
            reference2.putName(s2t("document"), origDocName);
            descriptor.putReference(s2t("to"), reference2);
            descriptor.putInteger(s2t("version"), 5);
            list.putInteger(0);
            descriptor.putList(s2t("ID"), list);
            executeAction(s2t("duplicate"), descriptor, DialogModes.NO);
        }

        function toggleLayerVisibility(toggleOptionsPalette) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var list = new ActionList();
            var reference = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            list.putReference(reference);
            descriptor.putList(s2t("null"), list);
            descriptor.putBoolean(s2t("toggleOptionsPalette"), toggleOptionsPalette);
            executeAction(s2t("show"), descriptor, DialogModes.NO);
        }

        function newDocFromLayer(docName) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            reference.putClass(s2t("document"));
            descriptor.putReference(s2t("null"), reference);
            descriptor.putString(s2t("name"), docName);
            reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("using"), reference2);
            descriptor.putInteger(s2t("version"), 0);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function unGroup() {
            function c2t(s) {
                return app.charIDToTypeID(s);
            }
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(c2t("null"), reference);
            executeAction(s2t("ungroupLayersEvent"), descriptor, DialogModes.NO);
        }

        function groupSelectedLayers() {
            function c2t(s) {
                return app.charIDToTypeID(s);
            }
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            reference.putClass(s2t("layerSection"));
            descriptor.putReference(c2t("null"), reference);
            reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("from"), reference2);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function copyLayerMask() {
            // Copy layer mask - preserving feather, density
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            descriptor.putClass(s2t("new"), s2t("channel"));
            reference.putEnumerated(s2t("channel"), s2t("channel"), s2t("mask"));
            reference.putName(s2t("layer"), destinationGroup); // Destination group name
            descriptor.putReference(s2t("at"), reference);
            reference2.putEnumerated(s2t("channel"), s2t("channel"), s2t("mask"));
            reference2.putName(s2t("layer"), sourceGroup); // Source group name
            descriptor.putReference(s2t("using"), reference2);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function selectForwardORBackwardLayer(makeVisible, forwardORbackward) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var list = new ActionList();
            var reference = new ActionReference();
            // "forwardEnum" or "backwardEnum"
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t(forwardORbackward));
            descriptor.putReference(s2t("null"), reference);
            // true or false
            descriptor.putBoolean(s2t("makeVisible"), makeVisible);
            list.putInteger(15);
            descriptor.putList(s2t("layerID"), list);
            executeAction(s2t("select"), descriptor, DialogModes.NO);
        }

        function removeGroup() {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("null"), reference);
            executeAction(s2t("delete"), descriptor, DialogModes.NO);
        }

        function pasteEffects(allowPasteFXOnLayerSet) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            descriptor.putBoolean(s2t("allowPasteFXOnLayerSet"), allowPasteFXOnLayerSet);
            executeAction(s2t("pasteEffects"), descriptor, DialogModes.NO);
        }
    }
    app.activeDocument.suspendHistory("Collapse Active Group.jsx", "main()");

} else {
    alert('You must have a document open!');
}

 

Participant
October 13, 2025

ur a legend.  

Participant
January 19, 2024

I use Photoshop Actions extensively and for more than a decade I've been using similar work-arounds found right here in this thread. I'm tired of work-arounds, I hope for a real solution for this someday.

I think this can be done using scripting. One day when I learn scripting life will be grand.

Inspiring
May 27, 2020
This is what I do to get around photoshop being an idiot. 
1) Have a known layer in each of your folders within photoshop. Call it "Dummy 1" and maybe "Dummy 2" for the next folder etc. They'll just be empty layers. When you have a layer outside of your folders that you need to be inside one of your folders, select your layer you'd like to move, and ctrl+click one of the dummy layers. So now you have two layers selected. Group them (ctrl + G) and then immediately ungroup them (ctrl + shift + G). The layer  you wanted to move should now be right under your dummy layer. It's important to know that the layer you're moving -must- be below the dummy layers to start with. Otherwise your dummy layer will move TO  your layer you want to move. 
2) An alternative is to select your group that doesn't contain your layer you want in it. Ungroup it. Now all the layers within that group are now selected. You can ctrl click the layer you want in the group and re-group the layers. Now your outside layer is part of that group. Although you'll have to rename the group again. 
I hope this helps people. 
Inspiring
April 21, 2020
I use collapsable groups within my actions by using a custom keyboard shortcut:

-Edit menu -> Keyboard Shortcuts
-Shortcuts for -> Panel Menus
-In the 'Layers' Group, select 'Collapse all Groups', and assign a keyboard shortcut (I use Cntl Opt Shift Command C)
-Use this keyboard shortcut at the end of an action, and all groups will be collapsed
Participating Frequently
October 31, 2018
Unfortunately this request is already open for 7 (seven) years now.
It shouldn't be sooooo difficult to implement a single option to open and close individual groups and being able to record them via an actionscript.
Does Adobe actually know and understand how easy it is to use actions?I guess not they just don't seem to want to understand the request of power users.
Sad, sad, sad...
Participating Frequently
August 22, 2018
For real.  This seems like a basic request.  I have tried all sorts of workarounds and have basically figured out how to manipulate opening and closing groups within an action, but it takes a lot of forethought and planning (at least for me).  It would be SO MUCH easier if there could be a menu item for:
1. Opening a single group (or selected groups)
2. Closing a single group (or selected groups)
3. Opening all groups
4.  Closing all groups* (already exists)

It makes no sense why there is only the option to close all groups.  None at all.  Please Fix it.
Inspiring
July 8, 2018
Thanks for your helpful posts. 🙂
Participant
March 14, 2017
during recording: if you manually move a layer above or under another layer in the same group (in the layers panel), recording this movement as part of the action, the group is kept open at the end of the action. It should work even if you and an action SELECTING a layer in the folder (without moving it), but i have to test this deeply.
davidg19038978
Known Participant
January 8, 2017

Another user request to enable recording an action to include expanding and collapsing on a per group basis.

If you select layers and create group from selected layers in an action the group is always collapsed. There is then no way in the action to open the group and use alt + [ or alt + ] to move up and down the layers within the group e.g. to turn visibility off.