Something similar to this: emacs-org mode and html publishing: how to change structure of generated HTML

I want to have more control on the layout of HTML files generated from org-mode files. The default layout is good, but not good enough for my needs.

How can I change the default layout for any custom one?

up vote 6 down vote accepted

A derived export backend is what you want. Here's an example where I've created a derived backend that changes the main html template.

In org-export-define-derived-backend you provide an alist with the parts of the backend you want to override.

In my backend I only wanted to replace the top level template.

(org-export-define-derived-backend 'pd-html 'html
     :translate-alist '((template . pd-html-template)))

pd-html-template is a function that takes the sub-elements and produces the final html. I'm just using basic string formatting and concatenation functions to produce the html. The following is a simplified implementation

(defun pd-html-template (contents info)
      "<!DOCTYPE html>\n"
      (format "<html lang=\"%s\">\n" (plist-get info :language))
      (format "<meta charset=\"%s\">\n"
       (coding-system-get org-html-coding-system 'mime-charset))
      (format "<title>%s</title>\n"
       (org-export-data (or (plist-get info :title) "") info))
      (format "<meta name=\"author\" content=\"%s\">\n"
       (org-export-data (plist-get info :author) info))
     "<link href=\"/css/style.css\" rel=\"stylesheet\" style=\"text/css\" />\n"
     (format "<h1 class=\"title\">%s</h1>\n"
       (org-export-data (or (plist-get info :title) "") info))

Other elements of the export backend can be customised in the same way; write a function that generates an output snippet and register in the translate-alist.

  • Instead of the nasty HTML interpolated format commands, Mustache.el is a cleaner way to go. – ocodo Apr 21 '15 at 1:37

Have a look at some of the HTML-derived exporter backends, for example

This uses org-export-define-derived-backend to customize how the HTML backend processes org files:

(org-export-define-derived-backend 'rss 'html
 '(?r "Export to RSS"
       ((?R "As RSS buffer"
        (lambda (a s v b) (org-rss-export-as-rss a s v)))
    (?r "As RSS file" (lambda (a s v b) (org-rss-export-to-rss a s v)))
    (?o "As RSS file and open"
        (lambda (a s v b)
          (if a (org-rss-export-to-rss t s v)
        (org-open-file (org-rss-export-to-rss nil s v)))))))
  '((:description "DESCRIPTION" nil nil newline)
    (:keywords "KEYWORDS" nil nil space)
    (:with-toc nil nil nil) ;; Never include HTML's toc
    (:rss-extension "RSS_EXTENSION" nil org-rss-extension)
    (:rss-image-url "RSS_IMAGE_URL" nil org-rss-image-url)
    (:rss-categories nil nil org-rss-categories))
  :filters-alist '((:filter-final-output . org-rss-final-function))
  :translate-alist '((headline . org-rss-headline)
             (comment . (lambda (&rest args) ""))
             (comment-block . (lambda (&rest args) ""))
             (timestamp . (lambda (&rest args) ""))
             (plain-text . org-rss-plain-text)
             (section . org-rss-section)
             (template . org-rss-template)))

in this, example :filters-alist '((:filter-final-output . org-rss-final-function)) is used to specify a function org-rss-final-function that can exclude some items from being exported.

Then, :translate-alist '((headline . org-rss-headline) ... defines a bunch of other functions for certain elements, in this case headlines. These functions will be called with the org data structure of the element, and return the corresponding HTML string.

With this, you should be able to define your own HTML-derived org exporter that outputs exactly what you want.

  • May can you insert a simpler code example? My elisp isn't good enough to dig the code you use as example! – shackra Apr 20 '15 at 5:34

This is my css file for org-to-HTML layout, and this is my configuration.

  • Not exactly what I'm looking for... – shackra Apr 20 '15 at 7:58
  • It's ordinary from other computer (I tested it just now), but it is very nice from my own Fedora (I made that configuration about a month ago), weird, I'll test it later. – CodyChan Apr 20 '15 at 10:00

Your Answer


By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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