How can I make all done (e.g. DONE) org-mode items "invisible"? I'm using org-mode's "visibility" terminology here, but what I'm referring to is collapsing (folding) those items closed, not making them literally invisible. I don't want to use org's sparse trees for this.

I have multiple custom done states (including SKIP, for example). I want items to be collapsed if they are in any of those states.

4 Answers 4


Combining two of the existing answers works well for me:

 (org-map-entries #'org-fold-hide-subtree
                "/+DONE" 'file 'archive 'comment)

Or to spell it out as M-x commands:

(defun my/org-hide-done-entries-in-region (start end)
  (interactive "r")
  (org-map-entries #'org-fold-hide-subtree
                   "/+DONE" 'region 'archive 'comment))

(defun my/org-hide-done-entries-in-buffer ()
  (org-map-entries #'org-fold-hide-subtree
                   "/+DONE" 'file 'archive 'comment))
  • That's quite an improvement over my horrible cut-n-paste code! Trying it for a bit then maybe I can mark this one accepted... Apr 6 at 13:36
  • Been using it myself for a while and seems to do the job.
    – JDS
    May 5 at 2:13
  • I just remembered a few days ago to get this into my work config where I actually use this more. Seems good so far. Looks like to cover multiple "complete" states one may have defined, the syntax is like this: "/+DONE|DELEGATED" May 10 at 18:19

You can archive all items you want folded.

Archived items (i.e. items marked with the ARCHIVE tag) will always remain folded unless explicitly unfolded via org-force-cycle-archived (C-TAB).

If you want to do a bulk archiving on all DONE items, there is an example here on how to proceed. Something like the following (untested):

  '(org-toggle-tag "ARCHIVE" 'on )
  "/+DONE" 'file 'archive 'comment)

This adds the ARCHIVE tag to all headings in the file having the DONE state (excluding commented and archived trees).

  • Thanks, interesting, though not exactly what I'm looking for: I think I just want to set the folded state as a one-off operation rather than changing the text of the buffer like this. I think I'll use archiving in some other cases, though, so good to know about it. Apr 30, 2016 at 11:08

The following command, minimally tested, will hide/fold all entries marked with one of the DONE keywords:

(defun org-fold-all-done-entries ()
  "Close/fold all entries marked DONE."
    (goto-char (point-max))
    (while (outline-previous-heading)
      (when (org-entry-is-done-p)

Note that the outline commands may be changing prefixes. If so, you may wish to change the hide-entry line to outline-hide-entry.

  • (hide-entry) doesn't hide the item for me, but (hide-subtree) does. I would edit the answer but I don't understand what you mean by "changing prefixes"? Also, in emacs 25 I don't have an outline-hide-entry (nor any functions whose names start with "outline-hide") Apr 30, 2016 at 11:15

This seems to work for me:

(defun my/org-get-folded-state ()
        ((not (or (org-at-item-p) (org-at-heading-p)))
            (let (eoh eol eos has-children children-skipped struct)
                ;; First, determine end of headline (EOH), end of subtree or item
                ;; (EOS), and if item or heading has children (HAS-CHILDREN).
                    (if (org-at-item-p)
                            (setq struct (org-list-struct))
                            (setq eoh (point-at-eol))
                            (setq eos (org-list-get-item-end-before-blank (point) struct))
                            (setq has-children (org-list-has-child-p (point) struct)))
                        (setq eoh (save-excursion (outline-end-of-heading) (point)))
                        (setq eos (save-excursion (org-end-of-subtree t t)
                                      (when (bolp) (backward-char)) (point)))
                        (setq has-children
                            (or (save-excursion
                                    (let ((level (funcall outline-level)))
                                        (and (org-at-heading-p t)
                                            (> (funcall outline-level) level))))
                                    (org-list-search-forward (org-item-beginning-re) eos t)))))
                    ;; Determine end invisible part of buffer (EOL)
                    (beginning-of-line 2)
                    (while (and (not (eobp)) ;; this is like `next-line'
                               (get-char-property (1- (point)) 'invisible))
                        (goto-char (next-single-char-property-change (point) 'invisible))
                        (and (eolp) (beginning-of-line 2)))
                    (setq eol (point)))
                    ((= eos eoh)
                    ((or (>= eol eos)
                         (not (string-match "\\S-" (buffer-substring eol eos))))

(defun my/org-tree-can-fold-p ()
    (not (member (my/org-get-folded-state) (list 'folded 'empty-node))))

(defun my/org-cycle-until-folded ()
    (while (my/org-tree-can-fold-p)

(defun my/org-hide-done-entries-in-range (start end)
        (goto-char end)
        (while (and (outline-previous-heading) (> (point) start))
            (when (org-entry-is-done-p)

(defun my/org-hide-done-entries-in-region (start end)
    (interactive "r")
    (my/org-hide-done-entries-in-range start end))

(defun my/org-hide-done-entries-in-buffer ()
    (my/org-hide-done-entries-in-range (point-min) (point-max)))
  • This works beautifully! Thank you! I added advice to run my/org-hide-done-entries-in-buffer after org-cycle-set-startup-visibility and it's perfect!
    – Emily
    May 16, 2023 at 18:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.