dtwrks / elm-book / ElmBook.Chapter

Chapters are what books are made of. They can be library guides, component examples, design tokens showcases, you name it.

Take a look at the "Chapters" guide for a few examples.

Getting started

Lets start by creating a chapter that displays different variants of a Button component:

module UI.Button exposing (docs, view)

import ElmBook.Actions exposing (logAction)
import ElmBook.Chapter exposing (Chapter, chapter, renderComponentList)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)

view :
    { label : String
    , disabled : Bool
    , onClick : msg
    }
    -> Html msg
view props =
    button
        [ class "px-8 py-3 rounded-md bg-indigo-200"
        , disabled props.disabled
        , onClick props.onClick
        ]
        [ text props.label ]

docs : Chapter x
docs =
    let
        props =
            { label = "Click me!"
            , disabled = False
            , onClick = logAction "Clicked button!"
            }
    in
    chapter "Buttons"
        |> renderComponentList
            [ ( "Default", view props )
            , ( "Disabled", view { props | disabled = True } )
            ]

Tip: Since Elm has amazing dead code elimination you don't need to worry about splitting your component examples from your source code. They can live side by side making your development experience much better!

chapter : String -> ChapterBuilder state html

Creates a chapter with some title.

chapterLink : { title : String, url : String } -> ElmBook.Internal.Chapter.ChapterCustom state html

Creates a chapter that links to an external resource.

Note: Chapter links are not like normal chapters – they are not rendered, they just serve as links to external resources through the book's navigation. Useful for things like linking to a library's elm-package page.

renderComponent : html -> ChapterBuilder state html -> ElmBook.Internal.Chapter.ChapterCustom state html

Render a single component with no markdown content.

renderComponentList : List ( String, html ) -> ChapterBuilder state html -> ElmBook.Internal.Chapter.ChapterCustom state html

Render a list of components with no markdown content.


type alias Chapter state =
ElmBook.Internal.Chapter.ChapterCustom state (Html (ElmBook.Internal.Msg.Msg state))

Defines a Chapter type. The argument is the shared state this chapter depends on. We can leave it blank (x) on stateless chapters. Read the "Stateful Chapters" guide to know more.


type alias ChapterBuilder state html =
ElmBook.Internal.Chapter.ChapterBuilder state html

The builder type for an incomplete chapter. Useful if you wanna reuse parts of your chapter setup pipeline across different chapters.

Markdown and embedded components

You're not limited to creating these "storybook-like" chapters though. Take a look at the functions below and you will understand how to create richer docs based on markdown and embedded components.

withComponent : html -> ChapterBuilder state html -> ChapterBuilder state html

Adds a component to your chapter. You can display it using markdown.

inputChapter : Chapter x
inputChapter =
    chapter "Input"
        |> withComponent (input [] [])
        |> render """

Take a look at this input:

<component />

"""

withComponentList : List ( String, html ) -> ChapterBuilder state html -> ChapterBuilder state html

Adds multiple components to your chapter. You can display them using markdown.

buttonsChapter : Chapter x
buttonsChapter =
    chapter "Buttons"
        |> withComponentList
            [ ( "Default", button [] [] )
            , ( "Disabled", button [ disabled True ] [] )
            ]
        |> render """

A button might be enabled:

<component with-label="Default" />

Or disabled:

<component with-label="Disabled"

"""

render : String -> ChapterBuilder state html -> ElmBook.Internal.Chapter.ChapterCustom state html

Used to create rich chapters with markdown and embedded components. Take a look at how you would list all buttons of the previous examples in one go:

buttonsChapter : Chapter x
buttonsChapter =
    chapter "Buttons"
        |> withComponentList
            [ ( "Default", button [] [] )
            , ( "Disabled", button [ disabled True ] [] )
            ]
        |> render """

    Look at all these buttons:

    <component-list />

"""

renderWithComponentList : String -> ChapterBuilder state html -> ElmBook.Internal.Chapter.ChapterCustom state html

Helper for creating chapters where all of the text content sits on top and all components at the bottom. It's basically an alias for what you just saw on the example above.

buttonsChapter : Chapter x
buttonsChapter =
    chapter "Buttons"
        |> withComponentList
            [ ( "Default", button [] [] )
            , ( "Disabled", button [ disabled True ] [] )
            ]
        |> renderWithComponentList
            "Look at all these buttons:"

Stateful Chapters

Create chapters with interactive components that can read and update the book's shared state. These functions work exactly like their stateless counterparts with the difference that they take the current state as an argument.

Take a look at the "Stateful Chapters" guide for a more throughout explanation.

withStatefulComponent : (state -> html) -> ChapterBuilder state html -> ChapterBuilder state html

Used for chapters with a single stateful component.

withStatefulComponentList : List ( String, state -> html ) -> ChapterBuilder state html -> ChapterBuilder state html

Used for chapters with multiple stateful components.

renderStatefulComponent : (state -> html) -> ChapterBuilder state html -> ElmBook.Internal.Chapter.ChapterCustom state html

Render a single stateful component with no markdown content.

renderStatefulComponentList : List ( String, state -> html ) -> ChapterBuilder state html -> ElmBook.Internal.Chapter.ChapterCustom state html

Render a list of stateful components with no markdown content.

withChapterInit : (state -> ( state, Platform.Cmd.Cmd (ElmBook.Internal.Msg.Msg state) )) -> ChapterBuilder state html -> ChapterBuilder state html

Use this to trigger a state change or command whenever this chapter is first rendered.

Customizing Chapters

withChapterOptions : List ElmBook.ChapterOptions.Attribute -> ChapterBuilder state html -> ChapterBuilder state html

By default, your chapter will display its title at the top of the content. You can disable this by passing in chapter options.

chapter "Buttons"
    |> withChapterOptions
        [ ElmBook.Chapter.hiddenTitle True
        ]
    |> renderComponentList
        [ ( "Default", view props )
        , ( "Disabled", view { props | disabled = True } )
        ]

Please note that chapter options are "inherited". So your chapters will inherit from the options passed to your book by ElmBook.withChapterOptions. Take a look at ElmBook.ChapterOptions for the options available.

withComponentOptions : List ElmBook.Internal.ComponentOptions.Attribute -> ChapterBuilder state html -> ChapterBuilder state html

By default, your components will appear inside a card with some padding and a label at the top. You can customize all of that with this function and the attributes available on ElmBook.Component.

chapter "Buttons"
    |> withComponentOptions
        [ ElmBook.Component.background "yellow"
        , ElmBook.Component.hiddenLabel True
        ]
    |> renderComponentList
        [ ( "Default", view props )
        , ( "Disabled", view { props | disabled = True } )
        ]

Please note that component options are "inherited". So your components will inherit from the options passed to your book by ElmBook.withComponentOptions and they can also be overriden on the component level. Take a look at the ElmBook.Component module for more details.