# AutoHtml turns plain text into HTML through composable filters

> AutoHtml is a Ruby gem that converts plain text into HTML using the pipes and filters pattern, where each filter implements a single call method and pipelines chain them. It bundles link, image, emoji, markdown, simple format and HTML escaping filters, and the pipeline order changes the result in ways the project documentation is careful to explain.

**dejan/auto_html** — Collection of filters that transform plain text into HTML code.

- Repository: https://github.com/dejan/auto_html
- Website: https://autohtml.makeme.tools
- Stars: 798 · Forks: 182
- Language: Ruby
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/dejan-auto-html

## Two objects, one interface, and that is the whole design

AutoHtml is a collection of filters that transform plain text into HTML code, and it borrows its structure from the Pipes and Filters processing design pattern.

The two concepts are short enough to state completely. A Filter transforms an input, and in this context it is any object that performs the transformation through a `#call(String)` method, with filter options passed in the initializer. A Pipeline is a composition of filters that transforms input by passing the output of one filter as the input of the next in line, and it is the `AutoHtml::Pipeline` class.

The elegant part is that a Pipeline implements the same `#call` interface, so a Pipeline is itself just another Filter. That means pipelines nest, and you can compose a pipeline of pipelines with other filters without any special handling. The project ships filters already, among them Link, Image and Markdown.

The practical upshot is that the transformation logic for user content lives in one object you can name, pass around and test, rather than in a sequence of ad hoc replacements inside a model.

The project is Ruby, MIT licensed, with the last push on 2026-08-11 and the current release v2.2.1 published on 2025-05-13, after v2.2.0 in January 2025 and v2.1.1 in February 2022. The homepage hosts a live demo.

## Filter order changes the output, and the examples show it

The most important thing to understand before using AutoHtml is that the order of filters in a pipeline is not cosmetic.

The documentation makes the point with a direct comparison. You want the `Image` filter before the `Link` filter so that the URL of an image gets transformed to an `img` tag and not an `a` tag. Put them the other way round and the image URL becomes a link around an image instead of an image.

The worked example builds this up in steps. A link filter is created with a target option and called on a line of text containing a URL. An emoji filter is created and called on a shortcode, producing an img tag pointing at a unicode emoji image. The two are then combined into a pipeline named base_format, and the combined call produces the linked text followed by the emoji image.

The final example nests them further. A new pipeline takes Markdown, then Image, then the earlier base_format, and the comment in that example is the one to carry into your own code, because it explains the whole failure mode: order matters, and the same input produces a different document depending on where a filter sits.

There is a subtlety worth checking in your own output. In the link filter example the generated markup shows the target attribute written as `target="blank"` rather than `target="_blank"`, so verify what your build actually emits before you rely on that attribute.

## Six bundled filters cover the common cases

The bundled list is short and each entry is given with its optional initialisation arguments and their default values.

`AutoHtml::Emoji` takes no documented options and converts emoji shortcodes into image tags. `AutoHtml::HtmlEscape` takes no documented options and handles escaping of the raw text. `AutoHtml::Image` accepts a proxy and an alt. `AutoHtml::Link` accepts target and rel. `AutoHtml::Markdown` and `AutoHtml::SimpleFormat` take no documented options.

That list is deliberately smaller than what a general HTML toolchain would offer. There is no sanitisation filter beyond HtmlEscape, no table filter, no code block filter, no heading filter. The filters that exist are the ones needed to turn a plain text comment or post into HTML with links, images and emoji in it.

Two implications follow. First, the escaping filter has to be placed deliberately in the pipeline, and the ActiveRecord example places HtmlEscape first, before Markdown, which is the safe ordering for user input. Second, if you need richer output than markdown, simple format, links, images and emoji, you write your own filter, because the interface is a single method and nothing more.

Writing a filter means implementing `#call` on an object that takes a string and returns a string. That is a low bar, and it is the extension point the whole library is built around.

## Storing the formatted output in a separate column

The documentation suggests an ActiveRecord pattern for using AutoHtml in a Rails application, and the reasoning behind it is performance rather than style.

The advice is to store the formatted output in the database, in a separate column, to avoid generating the same content on each access. The implementation is an overridden attribute writer:

```ruby
class Comment < ActiveRecord::Base
  FORMAT = AutoHtml::Pipeline.new(
    AutoHtml::HtmlEscape.new,
    AutoHtml::Markdown.new
  )

  def text=(t)
    super(t)
    self[:text_html] = FORMAT.call(t)
  end
end
```

Every time the `text` attribute is set, `text_html` is set as well, so a read never pays for the transformation. The example then shows a comment created with `comment = Comment.new(text: 'Hey!')` producing `comment.text_html` of `<p>Hey!</p>`.

The tradeoff is that the column holds a snapshot. If you change the pipeline later, previously stored rows still carry the old rendering until they are rewritten, so plan a backfill for a table with existing data.

The constant naming and the fact that the pipeline is built once at class load time are the details that matter for performance. Building the pipeline per request would defeat the point of storing the output.

## Installation is a Gemfile line, and the demo runs in Docker

Installing the gem in a Rails application means adding one line to the Gemfile:

```ruby
gem 'auto_html'
```

and then executing:

```bash
bundle
```

Or, if you are not using Bundler, installing it directly:

```bash
gem install auto_html
```

The repository also ships a demo application, and it is more substantial than a single script. The demo directory holds its own Gemfile and Gemfile.lock, a .ruby-version file, a Dockerfile, a config.ru, a docker-compose.yml, a deploy/ directory, a views/ directory, a public/ directory, its own lib/ and spec/ folders, and a README of its own. So the live demo at autohtml.makeme.tools is backed by a containerised application rather than a static page.

For development on the library itself, three commands are listed. Installing dependencies is `bundle install`. Running the linter is `rake rubocop`, and the repository has a .rubocop.yml file plus a .rspec file for the test runner configuration. Running the tests is `rake spec`.

The project is packaged as a gem with auto_html.gemspec, a Rakefile, a Gemfile.lock, a CHANGELOG.md and a MIT-LICENSE file at the root, and the source lives in lib/ with specs in spec/.

## Where AutoHtml sits against markdown libraries and sanitisation tools

It is worth being clear about what this library is not, because the name invites confusion.

It is not a markdown implementation. The `AutoHtml::Markdown` filter delegates to one, and `AutoHtml::SimpleFormat` is the Rails-style simple format conversion. What AutoHtml adds is the composition layer: a uniform interface, so that markdown, link detection, image detection and emoji can be combined and reordered as one object, with the ordering rule being part of the design rather than an accident.

It is also not a sanitiser. The bundled set has `AutoHtml::HtmlEscape` for escaping, and the project directs vulnerability reports to the repository's security policy rather than to public issues. But a sanitisation guarantee, where a whitelist of allowed tags is enforced regardless of filter order, is not one of the documented features.

The comparison with the Laravel-inspired approach that inspired it is instructive. A framework's own fixture and formatter helpers usually live inside the framework and are hard to compose or test in isolation. AutoHtml takes the same idea of small stateful formatters and makes each one a standalone object with one method, which means it can be used outside Rails, tested without a database, and swapped per use case.

That is the case for it. If you only need markdown, use a markdown library. If you need a named, testable, reusable transformation of user text into HTML that you can compose in a different order per context, this is the shape of tool that provides it.

## Conclusion

Adopt AutoHtml if you have user-submitted plain text that needs to become HTML in a Rails application and you want the transformation rules expressed as a composable pipeline rather than scattered string replacements. Skip it if you need a full text-to-HTML renderer with sanitisation guarantees beyond the bundled HtmlEscape filter, or if you would rather use a mature markdown parser directly and skip the filter layer. Verify first that the filter order you choose produces the output you expect, since the project documentation shows the same URL turning into an image tag rather than a link tag depending on where Image sits in the pipeline.

## FAQ

### How do I install AutoHtml in a Ruby application?

Add `gem 'auto_html'` to your Gemfile and run `bundle`, or install it directly with `gem install auto_html`. The gem is MIT licensed and published on RubyGems as auto_html.

### Which filters does AutoHtml bundle?

The bundled filters are AutoHtml::Emoji, AutoHtml::HtmlEscape, AutoHtml::Image with proxy and alt options, AutoHtml::Link with target and rel options, AutoHtml::Markdown and AutoHtml::SimpleFormat.

### Does the order of filters in an AutoHtml pipeline matter?

Yes. The documentation says you want Image before Link so that the URL of an image is transformed to an img tag and not an a tag, and it shows the same input producing different markup when the order changes.

## Sources

- [dejan/auto_html on GitHub](https://github.com/dejan/auto_html)
- [License: MIT](https://github.com/dejan/auto_html/blob/master/LICENSE)
- [Project website](https://autohtml.makeme.tools)
- [README](https://github.com/dejan/auto_html/blob/master/README.md)
- [Releases](https://github.com/dejan/auto_html/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dejan-auto-html
