diff --git a/Cargo.lock b/Cargo.lock
index d93c8c7c..3d556388 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -355,6 +355,7 @@ dependencies = [
  "helix-core",
  "helix-lsp",
  "helix-tui",
+ "log",
  "once_cell",
  "serde",
  "slotmap",
diff --git a/book/src/configuration.md b/book/src/configuration.md
index a025a48b..4528080b 100644
--- a/book/src/configuration.md
+++ b/book/src/configuration.md
@@ -1 +1,87 @@
 # Configuration
+
+## Theme
+
+Use a custom theme by placing a theme.toml in your config directory (i.e ~/.config/helix/theme.toml). The default theme.toml can be found [here](https://github.com/helix-editor/helix/blob/master/theme.toml), and user submitted themes [here](https://github.com/helix-editor/helix/blob/master/contrib/themes).
+
+Styles in theme.toml are specified of in the form:
+
+```toml
+key = { fg = "#ffffff", bg = "#000000", modifiers = ["bold", "italic"] }
+```
+
+where `name` represents what you want to style, `fg` specifies the foreground color, `bg` the background color, and `modifiers` is a list of style modifiers. `bg` and `modifiers` can be omitted to defer to the defaults.
+
+To specify only the foreground color:
+
+```toml
+key = "#ffffff"
+```
+
+if the key contains a dot `'.'`, it must be quoted to prevent it being parsed as a [dotted key](https://toml.io/en/v1.0.0#keys).
+
+```toml
+"key.key" = "#ffffff"
+```
+
+Possible modifiers:
+
+| modifier |
+| --- |
+| bold |
+| dim |
+| italic |
+| underlined |
+| slow\_blink |
+| rapid\_blink |
+| reversed |
+| hidden |
+| crossed\_out |
+
+Possible keys:
+
+| key | notes |
+| --- | --- |
+| attribute | |
+| keyword | |
+| keyword.directive | preprocessor directives (\#if in C) |
+| namespace | |
+| punctuation | |
+| punctuation.delimiter | |
+| operator | |
+| special | |
+| property | |
+| variable | |
+| variable.parameter | |
+| type | |
+| type.builtin | |
+| constructor | |
+| function | |
+| function.macro | |
+| function.builtin | |
+| comment | |
+| variable.builtin | |
+| constant | |
+| constant.builtin | |
+| string | |
+| number | |
+| escape | escaped characters |
+| label | used for lifetimes |
+| module | |
+| ui.background | |
+| ui.linenr | |
+| ui.statusline | |
+| ui.popup | |
+| ui.window | |
+| ui.help | |
+| ui.text | |
+| ui.text.focus | |
+| ui.menu.selected | |
+| warning | LSP warning |
+| error | LSP error |
+| info | LSP info |
+| hint | LSP hint |
+
+These keys match [tree-sitter scopes](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#theme). We half-follow the common scopes from [macromates language grammars](https://macromates.com/manual/en/language_grammars) with some differences.
+
+For a given highlight produced, styling will be determined based on the longest matching theme key. So it's enough to provide function to highlight `function.macro` and `function.builtin` as well, but you can use more specific scopes to highlight specific cases differently.
diff --git a/contrib/themes/README.md b/contrib/themes/README.md
new file mode 100644
index 00000000..1c9c5ae9
--- /dev/null
+++ b/contrib/themes/README.md
@@ -0,0 +1,9 @@
+# User submitted themes
+
+If you submit a theme, please include a comment at the top with your name and email address:
+
+```toml
+# Author : Name <email@my.domain>
+```
+
+We have a preview page for themes on our [wiki](https://github.com/helix-editor/helix/wiki/Themes)!
diff --git a/contrib/themes/ingrid.toml b/contrib/themes/ingrid.toml
new file mode 100644
index 00000000..60377b45
--- /dev/null
+++ b/contrib/themes/ingrid.toml
@@ -0,0 +1,46 @@
+# Author : Ingrid Rebecca Abraham <git@ingrids.email>
+
+"attribute" = "#839A53"
+"keyword" = { fg = "#D74E50", modifiers = ["bold"] }
+"keyword.directive" = "#6F873E"
+"namespace" = "#839A53"
+"punctuation" = "#C97270"
+"punctuation.delimiter" = "#C97270"
+"operator" = { fg = "#D74E50", modifiers = ["bold"] }
+"special" = "#D68482"
+"property" = "#89BEB7"
+"variable" = "#A6B6CE"
+"variable.parameter" = "#89BEB7"
+"type" = { fg = "#A6B6CE", modifiers = ["bold"] }
+"type.builtin" = "#839A53"
+"constructor" = { fg = "#839A53", modifiers = ["bold"] }
+"function" = { fg = "#89BEB7", modifiers = ["bold"] }
+"function.macro" = { fg = "#D4A520", modifiers = ["bold"] }
+"function.builtin" = "#89BEB7"
+"comment" = "#A6B6CE"
+"variable.builtin" = "#D4A520"
+"constant" = "#D4A520"
+"constant.builtin" = "#D4A520"
+"string" = "#D74E50"
+"number" = "#D74E50"
+"escape" = { fg = "#D74E50", modifiers = ["bold"] }
+"label" = "#D68482"
+
+"module" = "#839A53"
+
+"ui.background" = { bg = "#FFFCFD" }
+"ui.linenr" = { fg = "#bbbbbb" }
+"ui.statusline" = { bg = "#F3EAE9" }
+"ui.popup" = { bg = "#F3EAE9" }
+"ui.window" = { bg = "#D8B8B3" }
+"ui.help" = { bg = "#D8B8B3", fg = "#250E07" }
+
+"ui.text" = { fg = "#7B91B3" }
+"ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] }
+
+"ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" }
+
+"warning" = "#D4A520"
+"error" = "#D74E50"
+"info" = "#839A53"
+"hint" = "#A6B6CE"
diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml
index 0d28c82d..b2d1a594 100644
--- a/helix-view/Cargo.toml
+++ b/helix-view/Cargo.toml
@@ -28,3 +28,4 @@ slotmap = "1"
 
 serde = { version = "1.0", features = ["derive"] }
 toml = "0.5"
+log = "~0.4"
diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs
index 8b695898..efb6a1af 100644
--- a/helix-view/src/theme.rs
+++ b/helix-view/src/theme.rs
@@ -1,10 +1,11 @@
 use std::collections::HashMap;
 
+use log::warn;
 use serde::{Deserialize, Deserializer};
 use toml::Value;
 
 #[cfg(feature = "term")]
-pub use tui::style::{Color, Style};
+pub use tui::style::{Color, Modifier, Style};
 
 // #[derive(Clone, Copy, PartialEq, Eq, Default, Hash)]
 // pub struct Color {
@@ -115,6 +116,7 @@ impl<'de> Deserialize<'de> for Theme {
 }
 
 fn parse_style(style: &mut Style, value: Value) {
+    //TODO: alert user of parsing failures
     if let Value::Table(entries) = value {
         for (name, value) in entries {
             match name.as_str() {
@@ -128,6 +130,13 @@ fn parse_style(style: &mut Style, value: Value) {
                         *style = style.bg(color);
                     }
                 }
+                "modifiers" => {
+                    if let Value::Array(arr) = value {
+                        for modifier in arr.iter().filter_map(parse_modifier) {
+                            *style = style.add_modifier(modifier);
+                        }
+                    }
+                }
                 _ => (),
             }
         }
@@ -157,9 +166,34 @@ fn parse_color(value: Value) -> Option<Color> {
         if let Some((red, green, blue)) = hex_string_to_rgb(&s) {
             Some(Color::Rgb(red, green, blue))
         } else {
+            warn!("malformed hexcode in theme: {}", s);
             None
         }
     } else {
+        warn!("unrecognized value in theme: {}", value);
+        None
+    }
+}
+
+fn parse_modifier(value: &Value) -> Option<Modifier> {
+    if let Value::String(s) = value {
+        match s.as_str() {
+            "bold" => Some(Modifier::BOLD),
+            "dim" => Some(Modifier::DIM),
+            "italic" => Some(Modifier::ITALIC),
+            "underlined" => Some(Modifier::UNDERLINED),
+            "slow_blink" => Some(Modifier::SLOW_BLINK),
+            "rapid_blink" => Some(Modifier::RAPID_BLINK),
+            "reversed" => Some(Modifier::REVERSED),
+            "hidden" => Some(Modifier::HIDDEN),
+            "crossed_out" => Some(Modifier::CROSSED_OUT),
+            _ => {
+                warn!("unrecognized modifier in theme: {}", s);
+                None
+            }
+        }
+    } else {
+        warn!("unrecognized modifier in theme: {}", value);
         None
     }
 }
@@ -177,3 +211,39 @@ impl Theme {
         &self.scopes
     }
 }
+
+#[test]
+fn test_parse_style_string() {
+    let fg = Value::String("#ffffff".to_string());
+
+    let mut style = Style::default();
+    parse_style(&mut style, fg);
+
+    assert_eq!(style, Style::default().fg(Color::Rgb(255, 255, 255)));
+}
+
+#[test]
+fn test_parse_style_table() {
+    let table = toml::toml! {
+        "keyword" = {
+            fg = "#ffffff",
+            bg = "#000000",
+            modifiers = ["bold"],
+        }
+    };
+
+    let mut style = Style::default();
+    if let Value::Table(entries) = table {
+        for (_name, value) in entries {
+            parse_style(&mut style, value);
+        }
+    }
+
+    assert_eq!(
+        style,
+        Style::default()
+            .fg(Color::Rgb(255, 255, 255))
+            .bg(Color::Rgb(0, 0, 0))
+            .add_modifier(Modifier::BOLD)
+    );
+}