Problem statement

In Emacs org-mode, I am looking for a way to define #+EXPORT_EXCLUDE_TAGS (which defaults to :noexport) and #+EXPORT_SELECT_TAGS on a per-exporter basis, such that they apply only to specific exporters.

However, as far as I know, this functionality, which is detailed in the answer to this related question, applies globally to all org-mode exporters.


This problem arises from my desire to use the same org-mode source code to export to both,

  1. regular HTML (for a verbose 'textbook-style' document), and
  2. a Reveal.js presentation (which should be less verbose by excluding accordingly tagged sections). NB: For this I use org-re-reveal, but my question is more generically about "different exporters" (could also concern HTML vs. LaTeX export, for example).

Essentially, I am trying to mimic LaTeX Beamer's "article mode", which allows the use of markers such as \only<article>, \mode<presentation>, \mode<all>, etc. to make certain content only appear in specific documents, all of which are compiled from the same source.

What I imagine a solution to look like

My idea is to have org-mode code like the following:

* Some section
** Subsection content shows up in HTML, but not Reveal.js   :html:ignore:
- Foo
- Bla

** Subsection content shows up in Reveal.js, but not HTML   :reveal:ignore:
1. More
2. lists

** Subsection content shows up in both, HTML and Reveal.js  :reveal:html:ignore:
- Some
- text

This would require defining the tags :html and :reveal as exporter-specific #+EXPORT_SELECT_TAGS, but I don't know whether/how this is possible.

NB: The :ignore tag serves the purpose of excluding the subsection headings themselves in the export, whose sole purpose should be to control what is exported where. Of course if would be nice to include that functionality, too, in the definition of the :html and :reveal tags.

1 Answer 1


To achieve this

Subtree tagged with no_html are skipped for html export

Subtree tagged with no_rereveal are skipped for re-reveal export

Subtree tag with no_html is skipped for html export on

#+options: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline
#+options: author:nil broken-links:mark c:nil creator:nil
#+options: d:(not "LOGBOOK") date:t e:t email:nil f:t inline:t num:t
#+options: p:nil pri:nil prop:nil stat:t tags:t tasks:t tex:t
#+options: timestamp:t title:t toc:t todo:t |:t
#+title: Skip Headings based on Export Backend
#+language: en
#+select_tags: export
#+exclude_tags: noexport
#+creator: Emacs 30.0.50 (Org mode 9.6.14)

[[https://emacs.stackexchange.com/questions/80736/org-mode-per-exporter-select-tags-exclude-tags][org-mode: per-exporter ~#+SELECT_TAGS~ & ~#+EXCLUDE_TAGS?~]]

#+name: noexporttags
#+begin_src emacs-lisp :exports results :results value pp :wrap src elisp
  (thread-last org-export-registered-backends
           (seq-map 'org-export-backend-name)
           (seq-map 'no-export-tag-for-backend)
           (seq-sort 'string>))

#+CAPTION: No export tags for all registered backedns
#+RESULTS: noexporttags

#+name: org-export-current-backend
#+begin_src emacs-lisp :exports results :results value pp :wrap src elisp

#+CAPTION: Current backend
#+RESULTS: org-export-current-backend

#+name: no-export-tag-for-backend
#+begin_src emacs-lisp :exports results :results value pp :wrap src elisp
(no-export-tag-for-backend org-export-current-backend)

#+CAPTION: No export tag for current backend
#+RESULTS: no-export-tag-for-backend

#+name: versions
#+begin_src emacs-lisp :exports results :results value pp :wrap src elisp
  (list (format "emacs-%s" emacs-version)
    (format "org-%s" org-version))

#+CAPTION:  Produced with 
#+RESULTS: versions

* Some section
** Subsection content shows up in Reveal.js, but not HTML   :no_html:
- Foo
- Bla

** Subsection content shows up in HTML, but not Reveal.js   :no_rereveal:
1. More
2. lists

** Subsection content shows up in neither, HTML nor Reveal.js  :no_rereveal:no_html:
- Some
- text

use this

(defun no-export-tag-for-backend (backend)
  (thread-last backend
               (replace-regexp-in-string "[^#%@_[:alnum:]]" "")
               (concat "no_")))

(advice-add 'org-export--skip-p :around
            (defun my-org-export--skip-p (orig-fun &rest args)
              (or (apply orig-fun args)
                  (pcase-let* ((`(,datum ,options ,selected ,excluded) args)
                                (no-export-tag-for-backend org-export-current-backend)))
                    (pcase datum
                      ((and `(headline ,(map :tags) ,content)
                            (guard (seq-contains-p tags tag-for-skipping-current-backend)))

  • Thanks, this is an excellent step in the right direction! I now realize both the question title as well as my use of the :ignore: tag in my "imagined solution" might have slightly confused the fact that I was primarily interested in the 'opposite' use case, i.e., to define tags for explicit INclusion (not: EXclusion) of a given section for a given exporter. Not a big deal, but what I'm wondering about: Did you just decide ad-hoc to implement per-exporter exclude tags, or did you do so because it would be inherently harder to implement per-exporter include tags?
    – Florian H.
    Commented Apr 2 at 20:31
  • I took the liberty of editing the org-mode subsection headings such as to correctly reflect the actually implemented behavior (i.e., per-exporter exclude tags).
    – Florian H.
    Commented Apr 2 at 20:35
  • I am awarding the bounty on the grounds that the title and problem statement imply that per-exporter exclude tags are one of two valid solutions to the problem. However, to accept this as the answer, I'd like to suggest the following edits: (1) A clearer description of the steps that need to be taken to run the above example (e.g., adding code to init.el, plus org-mode export commands). (2) Either an addition of an implementation for the opposite behavior (i.e., per-exporter include tags), or a rationale why such a behavior would not be desirable or easily feasible.
    – Florian H.
    Commented Apr 2 at 20:41

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.