https://blog.noredink.com/post/699829728548372480/svgs-as-elm-code
NoRedInk
* [ ]
* We're hiring!
* Team
* noredink.com
1 day ago
SVGs as Elm Code
Moving SVGs out of the file system and into regular Elm code can make
icons easier to manage, especially if you find you need to make
accessibility improvements.
Imagine we have an arbitrary SVG file straight from our Design team's
tools:
Notice that there's lots of extraneous information in the SVG --
including some information that's distinctly unhelpful! The title of
the SVG ends up being used as the accessible name of the SVG -- it's
more or less equivalent to an img tag's alt. A title of
"star-outline" will not help our users to understand what this icon
is supposed to represent.
Compare the raw SVG value to what it might look like if rewritten as
Elm code and tidied-up by a human developer:
import Svg exposing (..)
import Svg.Attributes exposing (..)
starOutline : Svg msg
starOutline =
svg
[ x "0px"
, y "0px"
, viewBox "0 0 21 21"
]
[ Svg.path
[ fill "#FFF"
, stroke "#146AFF"
, strokeWidth "2"
, d "M11.1,1.4l2.4,4.8c0.1,0.2,0.3,0.4,0.6,0.4l5.2,0.8c0.4,0.1,0.7,0.4,0.6,0.8 c0,0.2-0.1,0.3-0.2,0.4l-3.8,3.8c-0.2,0.2-0.2,0.4-0.2,0.6l0.9,5.3c0.1,0.4-0.2,0.8-0.6,0.8c-0.2,0-0.3,0-0.5-0.1l-4.7-2.5 c-0.2-0.1-0.5-0.1-0.7,0l-4.7,2.5c-0.4,0.2-0.8,0.1-1-0.3c-0.1-0.1-0.1-0.3-0.1-0.5l0.9-5.3c0-0.2,0-0.5-0.2-0.6L1.2,8.7 c-0.3-0.3-0.3-0.8,0-1c0.1-0.1,0.3-0.2,0.4-0.2l5.2-0.8c0.2,0,0.4-0.2,0.6-0.4l2.4-4.8c0.2-0.4,0.6-0.5,1-0.3 C10.9,1.1,11,1.3,11.1,1.4z"
]
[]
]
Example 1 Ellie link
Once the SVG is rewritten in Elm, we can leverage the Elm type system
to guarantee that icons in our application are always rendered in a
consistent way. By exposing the Icon type but not exposing the Icon
constructor, we can ensure that there's only one way to produce HTML
from an Icon. This strategy is the opaque type pattern, which you can
learn more about in former NoRedInk engineer Charlie Koster's blog
post series on advanced types in Elm and in the Elm Radio podcast's
Intro to Opaque Types episode.
module Icons exposing (Icon, toHtml, starOutline)
type Icon =
-- `Never` is used here so that our Icon type doesn't need a type hole. Essentially, the `Never` is saying "this kind of Svg cannot produce messages ever"
Icon (Svg Never)
toHtml : Icon -> Html msg
toHtml (Icon icon) =
-- "Html.map never" transforms `Svg msg` into `Svg Never`
Html.map never icon
starOutline : Icon -- notice the type changed
starOutline =
svg
...
|> Icon
Now that we've got consistently-rendered icons, we can start thinking
about what an accessible way to render the SVGs might be. Carie
Fisher's article Accessible SVGs - Perfect Patterns For Screen Reader
Users is the resource to use when considering how to render SVGs in
an accessible way. We will be using Pattern 5,