Material

Custom spans in Org mode

Org mode's HTML export lets you use #+BEGIN_... and #+END_... blocks for custom <div> classes, but what about custom <span> classes? There are some ways to do it, but they all move the text out of the normal document flow, which makes reading the source difficult. Instead, you can use org-add-link-type, usually a way to register custom link schemes. Org links are inline and quite readable, and there is a notion of a link that isn't clickable, so it's not too much semantic abuse.

(defun jw/html-escape-attribute (value)
  "Entity-escape VALUE and wrap it in quotes."
  ;; http://www.w3.org/TR/2009/WD-html5-20090212/serializing-html-fragments.html
  ;;
  ;; "Escaping a string... consists of replacing any occurrences of
  ;; the "&" character by the string "&amp;", any occurrences of the
  ;; U+00A0 NO-BREAK SPACE character by the string "&nbsp;", and, if
  ;; the algorithm was invoked in the attribute mode, any occurrences
  ;; of the """ character by the string "&quot;"..."
  (let* ((value (replace-regexp-in-string "&" "&amp;" value))
         (value (replace-regexp-in-string "\u00a0" "&nbsp;" value))
         (value (replace-regexp-in-string "\"" "&quot;" value)))
    value))


(eval-after-load "org"
  '(org-add-link-type
    "span" #'ignore ; not an 'openable' link
    #'(lambda (class desc format)
        (pcase format
          (`html (format "<span class=\"%s\">%s</span>"
                         (jw/html-escape-attribute class)
                         (or desc "")))
          (_ (or desc ""))))))

Now you can type links such as:

Check out this [[span:special][text block]].

Which generates HTML output like:

<p>Check out this <span class="special">text block</span>.</p>