# Elm Integration Guide
## API Guide & Compiler Configuration
The API for the `astro-integration-elm` package is very minimal, as only one function, the integration, is exported. The typescript typings for this are pretty weak currently, but the arguments are just forwarded to [rtfeldman/node-elm-compiler](https://github.com/rtfeldman/node-elm-compiler).
The integration will automatically run the Elm compiler in optimised mode when you run a full (non dev) build. You can override this, or add other Elm compiler settings to the integration as parameters to the `elm()` function.
## Using Flags
Astro `props` map very neatly onto Elm `flags`, and an Astro component (or island) is a good fit for an Elm `element`. The integration simply calls the `init` function, which can take the props as either:
- A `Json.Decode.Value`, which you can **safely** de-serialize as you would regular JSON.
- A custom record type, which will be **unsafely** converted from JSON to an Elm type (automatically).
Both of these approaches look the same from the Astro side, which one you are using depends on the type of your `init` function:
```elm
import Json.Decode
init : Decode.Value -> ( Model, Cmd msg )
-- vs --
init : { class : Maybe String, count : Int } -> ( Model, Cmd msg )
```
Using a custom record type is **dangerous** if you're server side rendering: if the wrong types are passed, your page will not render for that request. However, if you're generating a static site, it's safe to use record types - an issue with the flag types will only cause a "build time error".
## Default Flags (`class` & `server`)
The integration automatically adds a flag, called `"server"`, which is set to `true` when your component is being rendered on the server and false if on the client-side.
If a `
```
```elm
module StyledComponent exposing (..)
import Html exposing (div)
import Html.Attributes exposing (class, id)
init : { class : String } -> ( { class : String }, Cmd msg )
-- ...
view model =
div
[ class model.class
, id "my-elm-component"
]
[ -- ...
]
```
## More Complex Example: Props & `client:load`
_index.astro_
```jsx
---
import Counter from "../components/Counter.elm";
---
Astro and Elm:
```
_Counter.elm_
```elm
module Counter exposing (main)
import Browser
import Html exposing (button, div, text)
import Html.Events exposing (onClick)
import Json.Decode as D
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
init : D.Value -> ( Model, Cmd msg )
init flags =
( Result.withDefault 0 <| D.decodeValue flagsDecoder flags
, Cmd.none
)
flagsDecoder : D.Decoder Int
flagsDecoder =
(D.field "count" D.int)
type Msg = Inc | Dec
update msg count =
case msg of
Inc -> (count + 1, Cmd.none)
Dec -> (count - 1, Cmd.none)
view count =
div
[ text <| toString count
, button [ onClick Inc ] [ text "+" ]
, button [ onClick Dec ] [ text "-" ]
]
```
## Which kinds of Elm program can I include?
Elm's `Browser` module contains 4 functions to create an Elm program.
- `Browser.sandbox`
- `Browser.element`
- `Browser.document`
- `Browser.application`
You can `sandbox` & `element` with ease. Using `document` is more nuanced, as it takes over the DOM's `document.body` element. It will work, but it will remove all body content in your Astro file, so be careful! You can only use one `document` at a time, which I suppose makes sense.
The `application` function is not supported, as it is designed for SPAs, and doesn't appear to be a good fit for Astro. This may change in a future release.
## Advanced: Using `ports`
Elm's ports are a great way to use web APIs that aren't available in Elm.
However, Astro [doesn't allow passing functions to hybrid props](https://guide.elm-lang.org/interop/ports.html).
The (less than ideal) solution I offer is to use the `unsafeSetup` prop.
**This is highly dangerous!**
```jsx
{
var socket = new WebSocket('wss://echo.websocket.org')
app.ports.sendMessage.subscribe(function(message) {
socket.send(message);
})
socket.addEventListener("message", (event) => {
app.ports.messageReceiver.send(event.data);
})
}`}
/>
```
Here we can establish an (incoming and outgoing) websocket connection to the server with the `unsafeSetup` function.
The `unsafeSetup` function is evaluated **in the client's browser** with `eval`.
This can be a **huge security vulnerability**. Do not allow interpolate user-generated, external or unescaped content into the `unsafeSetup` prop.
🚨 I repeat - **do not** put anything except trusted code in this string.
Much like Astro's [`set:html`](https://docs.astro.build/en/reference/directives-reference/#sethtml) or React's `dangerouslySetInnerHTML`, this opens you up to XSS attacks.