diff --git a/intro/part4/README.md b/intro/part4/README.md
new file mode 100644
index 0000000..bd69f36
--- /dev/null
+++ b/intro/part4/README.md
@@ -0,0 +1,21 @@
+# Part 3
+
+This is just like last time, except first we'll install the `elm/browser` package so we can create an interactive app in the browser, instead of static HTML.
+
+To install the package, `cd` into the `part3/` directory and run:
+
+```shell
+elm install elm/browser
+```
+
+Then build everything the same way as last time:
+
+```shell
+elm make src/Main.elm --output elm.js
+```
+
+Finally, open `index.html` in your browser.
+
+## Exercise
+
+Open `src/Main.elm` in your editor and resolve the TODOs there.
diff --git a/intro/part4/elm-package.json b/intro/part4/elm-package.json
new file mode 100644
index 0000000..f5ba1c5
--- /dev/null
+++ b/intro/part4/elm-package.json
@@ -0,0 +1,15 @@
+{
+ "version": "1.0.0",
+ "summary": "helpful summary of your project, less than 80 characters",
+ "repository": "https://github.com/user/project.git",
+ "license": "BSD3",
+ "source-directories": [
+ "."
+ ],
+ "exposed-modules": [],
+ "dependencies": {
+ "elm-lang/core": "5.1.1 <= v < 6.0.0",
+ "elm-lang/html": "2.0.0 <= v < 3.0.0"
+ },
+ "elm-version": "0.18.0 <= v < 0.19.0"
+}
diff --git a/intro/part4/elm.json b/intro/part4/elm.json
new file mode 100644
index 0000000..dd41cae
--- /dev/null
+++ b/intro/part4/elm.json
@@ -0,0 +1,24 @@
+{
+ "type": "application",
+ "source-directories": [
+ "src"
+ ],
+ "elm-version": "0.19.0",
+ "dependencies": {
+ "direct": {
+ "elm/browser": "1.0.0",
+ "elm/core": "1.0.0",
+ "elm/html": "1.0.0"
+ },
+ "indirect": {
+ "elm/json": "1.0.0",
+ "elm/time": "1.0.0",
+ "elm/url": "1.0.0",
+ "elm/virtual-dom": "1.0.0"
+ }
+ },
+ "test-dependencies": {
+ "direct": {},
+ "indirect": {}
+ }
+}
\ No newline at end of file
diff --git a/intro/part4/index.html b/intro/part4/index.html
new file mode 100644
index 0000000..3860a04
--- /dev/null
+++ b/intro/part4/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+ Elm Workshop
+
+
+
+
+
+
+
+
diff --git a/intro/part4/src/Article.elm b/intro/part4/src/Article.elm
new file mode 100644
index 0000000..833e956
--- /dev/null
+++ b/intro/part4/src/Article.elm
@@ -0,0 +1,21 @@
+module Article exposing (feed, tags)
+
+-- For now, this module only holds hardcoded data.
+--
+-- In future exercises, it will read data from the server!
+
+
+tags =
+ [ "elm"
+ , "fun"
+ , "programming"
+ , "dragons"
+ ]
+
+
+feed =
+ [ { title = "Elm is fun!", description = "Elm", body = "I've really been enjoying it!", tags = [ "elm", "fun" ], slug = "elm-is-fun--zb6nba" }
+ , { title = "Who says undefined isn't a function anyway?", description = "Functions", body = "Quite frankly I think undefined can be anything it wants to be,if it believes in itself.", slug = "who-says-undefined-isnt-a-function-anyway-t39ope", tags = [ "programming" ] }
+ , { title = "This compiler is pretty neat", description = "Elm", body = "It tells me about problems in my code. How neat is that?", tags = [ "compilers", "elm" ], slug = "this-compiler-is-pretty-neat-9ycui8" }
+ , { title = "Are dragons real?", description = "dragons", body = "Do Komodo Dragons count? I think they should. It's right there in the name!", tags = [ "dragons" ], slug = "are-dragons-real-467lsh" }
+ ]
diff --git a/intro/part4/src/Main.elm b/intro/part4/src/Main.elm
new file mode 100644
index 0000000..ba447ff
--- /dev/null
+++ b/intro/part4/src/Main.elm
@@ -0,0 +1,148 @@
+module Main exposing (main)
+
+import Article
+import Browser
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (onClick)
+
+
+-- MODEL
+
+
+type alias Model =
+ { tags : List String
+ , selectedTag : String
+
+ {- 👉 TODO: change this `allArticles` annotation to the following:
+
+ allArticles : List Article
+
+
+ 💡 HINT: You'll need to move the existing annotation to a `type alias`.
+ -}
+ , allArticles :
+ List
+ { title : String
+ , description : String
+ , body : String
+ , tags : List String
+ , slug : String
+ }
+ }
+
+
+{-| 👉 TODO: Replace this comment with a type annotation for `initialModel`
+-}
+initialModel =
+ { tags = Article.tags
+ , selectedTag = "elm"
+ , allArticles = Article.feed
+ }
+
+
+
+-- UPDATE
+
+
+type alias Msg =
+ { description : String
+ , data : String
+ }
+
+
+{-| 👉 TODO: Replace this comment with a type annotation for `update`
+-}
+update msg model =
+ if msg.description == "ClickedTag" then
+ { model | selectedTag = msg.data }
+ else
+ model
+
+
+
+-- VIEW
+
+
+{-| 👉 TODO: Replace this comment with a type annotation for `view`
+-}
+view model =
+ let
+ articles =
+ List.filter (\article -> List.member model.selectedTag article.tags)
+ model.allArticles
+
+ feed =
+ List.map viewArticle articles
+ in
+ div [ class "home-page" ]
+ [ viewBanner
+ , div [ class "container page" ]
+ [ div [ class "row" ]
+ [ div [ class "col-md-9" ] feed
+ , div [ class "col-md-3" ]
+ [ div [ class "sidebar" ]
+ [ p [] [ text "Popular Tags" ]
+ , viewTags model
+ ]
+ ]
+ ]
+ ]
+ ]
+
+
+{-| 👉 TODO: Replace this comment with a type annotation for `view`
+-}
+viewArticle article =
+ div [ class "article-preview" ]
+ [ h1 [] [ text article.title ]
+ , p [] [ text article.description ]
+ , span [] [ text "Read more..." ]
+ ]
+
+
+{-| 👉 TODO: Replace this comment with a type annotation for `view`
+-}
+viewBanner : Html Msg
+viewBanner =
+ div [ class "banner" ]
+ [ div [ class "container" ]
+ [ h1 [ class "logo-font" ] [ text "conduit" ]
+ , p [] [ text "A place to share your knowledge." ]
+ ]
+ ]
+
+
+{-| 👉 TODO: Replace this comment with a type annotation for `view`
+-}
+viewTag selectedTagName tagName =
+ let
+ otherClass =
+ if tagName == selectedTagName then
+ "tag-selected"
+ else
+ "tag-default"
+ in
+ button
+ [ class ("tag-pill " ++ otherClass)
+ , onClick { description = "ClickedTag", data = tagName }
+ ]
+ [ text tagName ]
+
+
+viewTags : Model -> Html Msg
+viewTags model =
+ div [ class "tag-list" ] (List.map (viewTag model.selectedTag) model.tags)
+
+
+
+-- MAIN
+
+
+main : Program () Model Msg
+main =
+ Browser.sandbox
+ { init = initialModel
+ , view = view
+ , update = update
+ }