androidhtmltextviewtagssettext

Supported html tags on Android TextView


I need an official list of supported HTML tags on Android TextView. I'm using textView.setText(Html.fromHtml(label)); but I don't know which tags are supported.


Solution

  • Note:

    This targets API 27. Earlier versions are NOT guaranteed to support the tags seen in this list, and same for later ones (they could be removed). See the equivalent class for the applicable API versions for the applicable list.


    It seems these aren't documented anywhere (correction, 2021: no longer the case), and there isn't a concrete list of when tags are added (2021: this still appears to be the case). I figured the HTML tags would need to be declared somewhere, if not in the docs, at least in the code. Fortunately, Android's HTML parsing is straight-forward enough to easily understand the relevant bits without dumpster-diving too much.

    For future versions: you can either use IntelliJ or some other IDE to explore the source code of Html.java, or you can always go to the AOSP site or the equivalent GitHub repository. Using an IDE is potentially the easiest option.

    Html#fromHtml(String, int) calls Html#fromHtml(String, Int, ImageGetter, TagHandler. The last method creates a HtmlToSpannedConverter, and returns the result of the conversion. I dug into that code, and I found this method:

    private void handleStartTag(String tag, Attributes attributes) {
    
        if (tag.equalsIgnoreCase("br")) {
            // We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
            // so we can safely emit the linebreaks when we handle the close tag.
        } else if (tag.equalsIgnoreCase("p")) {
            startBlockElement(mSpannableStringBuilder, attributes, getMarginParagraph());
            startCssStyle(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("ul")) {
            startBlockElement(mSpannableStringBuilder, attributes, getMarginList());
        } else if (tag.equalsIgnoreCase("li")) {
            startLi(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("div")) {
            startBlockElement(mSpannableStringBuilder, attributes, getMarginDiv());
        } else if (tag.equalsIgnoreCase("span")) {
            startCssStyle(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("strong")) {
            start(mSpannableStringBuilder, new Bold());
        } else if (tag.equalsIgnoreCase("b")) {
            start(mSpannableStringBuilder, new Bold());
        } else if (tag.equalsIgnoreCase("em")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("cite")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("dfn")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("i")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("big")) {
            start(mSpannableStringBuilder, new Big());
        } else if (tag.equalsIgnoreCase("small")) {
            start(mSpannableStringBuilder, new Small());
        } else if (tag.equalsIgnoreCase("font")) {
            startFont(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("blockquote")) {
            startBlockquote(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("tt")) {
            start(mSpannableStringBuilder, new Monospace());
        } else if (tag.equalsIgnoreCase("a")) {
            startA(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("u")) {
            start(mSpannableStringBuilder, new Underline());
        } else if (tag.equalsIgnoreCase("del")) {
            start(mSpannableStringBuilder, new Strikethrough());
        } else if (tag.equalsIgnoreCase("s")) {
            start(mSpannableStringBuilder, new Strikethrough());
        } else if (tag.equalsIgnoreCase("strike")) {
            start(mSpannableStringBuilder, new Strikethrough());
        } else if (tag.equalsIgnoreCase("sup")) {
            start(mSpannableStringBuilder, new Super());
        } else if (tag.equalsIgnoreCase("sub")) {
            start(mSpannableStringBuilder, new Sub());
        } else if (tag.length() == 2 &&
                Character.toLowerCase(tag.charAt(0)) == 'h' &&
                tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
            startHeading(mSpannableStringBuilder, attributes, tag.charAt(1) - '1');
        } else if (tag.equalsIgnoreCase("img")) {
            startImg(mSpannableStringBuilder, attributes, mImageGetter);
        } else if (mTagHandler != null) {
            mTagHandler.handleTag(true, tag, mSpannableStringBuilder, mReader);
        }
    }
    

    Which does contain all of the supported HTML tags. This list might change in future versions (it did from the original answer I had), but you can dig through the source yourself to find it in later versions. With the above code, this is the currently supported list:

    br
    p
    ul
    li
    div
    span
    strong
    b
    em
    cite
    dfn
    i
    big
    small
    font
    blockquote
    tt
    a
    u
    del
    s
    strike 
    sub
    sup
    img 
    h1
    h2
    h3
    h4
    h5
    h6
    

    Further methods cover supported attributes (in <a href="">, href is an attribute):


    img:

    src
    

    font:

    color
    face
    

    size is apparently not supported.


    a:

    href
    

    p, ul, and div calls startBlockElement, which gives one attrib:

    text-align
    

    Something special worth noting about this is the supported align variables.

    start and end might be inverted in RTL layouts - I haven't tested.


    span and p, and li calls startCssStyle, which gives access to the following style attributes:

    text-decoration
    background-color or background
    color
    

    text-decoration seems to be limited to line-through.