# Slime [![Continuous Integration][github-img]][github] [![Hex Version][hex-img]][hex] [![License][license-img]][license]
[github-img]: https://github.com/slime-lang/slime/actions/workflows/ci.yml/badge.svg
[github]: https://github.com/slime-lang/slime/actions/workflows/ci.yml
[hex-img]: https://img.shields.io/hexpm/v/slime.svg
[hex]: https://hex.pm/packages/slime
[license-img]: http://img.shields.io/badge/license-MIT-brightgreen.svg
[license]: http://opensource.org/licenses/MIT
> A refreshing way to slim down your markup in Elixir.
Slime is an [Elixir][elixir] library for rendering [Slim][slim]-like
templates as HTML.
For use with [Phoenix][phoenix], please see [PhoenixSlime][phoenix-slime].
[slim]: http://slim-lang.com
[elixir]: http://elixir-lang.com
[phoenix]: http://www.phoenixframework.org/
[phoenix-slime]: https://github.com/slime-lang/phoenix_slime
Easily turn this:
```slim
doctype html
html
head
meta name="keywords" description="Slime"
title = site_title
javascript:
alert('Slime supports embedded javascript!');
body
#id.class
ul
= Enum.map [1, 2], fn x ->
li = x
```
Into this:
```html
<!DOCTYPE html>
<html>
<head>
<meta name="keywords" description="Slime">
<title>Website Title</title>
<script>alert('Slime supports embedded javascript!');</script>
</head>
<body>
<div class="class" id="id">
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
</body>
</html>
```
With this:
```elixir
Slime.render(source, site_title: "Website Title")
```
## Reference
### Attributes
Attributes can be assigned in a similar fashion to regular HTML.
```slim
a href="elixir-lang.org" target="_blank" Elixir
```
```html
<a href="elixir-lang.org" target="_blank">Elixir</a>
```
Elixir expressions can be used as attribute values using the interpolation
syntax.
```slim
a href="#{my_variable}" Elixir
```
```html
<a href="elixir-lang.org">Elixir</a>
```
Boolean attributes can be set using boolean values
```slim
input type="checkbox" checked=true
input type="checkbox" checked=false
```
```html
<input type="checkbox" checked>
<input type="checkbox">
```
There is a literal syntax for class and id attributes
```slim
.foo.bar
select.bar
#foo
body#bar
```
```html
<div class="foo bar"></div>
<select class="bar"></select>
<div id"foo"></div>
<body id="bar"></body>
```
### Code
Elixir can be written inline using `-` and `=`.
`-` evalutes the expression.
`=` evalutes the expression, and then inserts the value into template.
```slim
- number = 40
p = number + 2
```
```html
<p>42</p>
```
The interpolation syntax can be used to insert expressions into text.
```slim
- name = "Felix"
p My cat's name is #{name}
```
```html
<p>My cat's name is Felix</p>
```
### Comments
Lines can be commented out using the `/` character.
```slim
/ p This line is commented out
p This line is not
```
```html
<p>This line is not</p>
```
HTML `<!-- -->` comments can be inserted using `/!`
```slim
/! Hello, world!
```
```html
<!-- Hello, world! -->
```
### Conditionals
We can use the regular Elixir flow control such as the `if` expression.
```slim
- condition = true
= if condition do
p It was true.
- else
p It was false.
```
```html
<p>It was true.</p>
```
### Doctype
There are shortcuts for common doctypes.
```slim
doctype html
doctype xml
doctype transitional
doctype strict
doctype frameset
doctype 1.1
doctype basic
doctype mobile
```
```html
<!DOCTYPE html>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
```
### Iteration
Elixir's collection manipulation expressions can be used to iterate over
collections in your templates.
```slim
- names = ["Sarah", "Mia", "Harry"]
/! Enum.map
= Enum.map names, fn name ->
p = name
/! for comprehension
= for name <- names do
h1 = name
```
```html
<!-- Enum.map -->
<p>Sarah</p>
<p>Mia</p>
<p>Harry</p>
<!-- for comprehension -->
<h1>Sarah</h1>
<h1>Mia</h1>
<h1>Harry</h1>
```
### Embedded engines
Examples:
```slim
javascript:
console.log("Test javascript");
css:
body {
color: black;
}
elixir:
a = [1, 2, 3]
b = Enum.map(a, &(&1 + 1))
eex:
Hello from <%= "eex" %>
```
You can define your own embedded engine in slime application config:
```elixir
# config.exs
config :slime, :embedded_engines, %{
markdown: MyApp.MarkdownEngine
}
# markdown_engine.ex
defmodule MyApp.MarkdownEngine do
@behaviour Slime.Parser.EmbeddedEngine
def render(text, _options) do
Earmark.to_html(text)
end
end
```
Because the engines are being read on compile time you need to recompile
the library after you have added new engines. You can do this by:
```bash
mix deps.compile slime --force
```
## Precompilation
Templates can be compiled into module functions like EEx templates, using
functions `Slime.function_from_file/5` and
`Slime.function_from_string/5`.
To use slime templates (and Slime) with
[Phoenix][phoenix], please see
[PhoenixSlim][phoenix-slime].
[phoenix]: http://www.phoenixframework.org/
[phoenix-slime]: https://github.com/slime-lang/phoenix_slime
## Differences to Ruby Slim
We aim for feature parity with the original [Slim](http://slim-lang.com)
implementation, but we deviate in some respects. We do this to be true to
Elixir – just like the original Slim implementation is true to its Ruby
foundations.
For example, in Slime you do
```slim
= if condition do
p It was true.
- else
p It was false.
```
where Ruby Slim would do
```slim
- if condition
p It was true.
- else
p It was false.
```
Note the `do` and the initial `=`, because we render the return value of the
conditional as a whole.
## Debugging
If you have trouble locating exceptions in Slime templates, you can add
```elixir
config :slime, :keep_lines, true
```
to your `config.exs` file. With this option Slime will keep original template lines in result `eex` and `html`. Keep in mind, that output is slightly different from default Slime output, for example `|` works like `'`, and empty lines are not ignored.
## Contributing
Feedback, feature requests, and fixes are welcomed and encouraged. Please
make appropriate use of [Issues][issues] and [Pull Requests][pulls]. All code
should have accompanying tests.
[issues]: https://github.com/slime-lang/slime/issues
[pulls]: https://github.com/slime-lang/slime/pulls
## License
MIT license. Please see [LICENSE][license] for details.
[LICENSE]: https://github.com/slime-lang/slime/blob/master/LICENSE