diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 8c9c2aa3a11c7bf314fad3ff74c78b7557697de2..e71fd1b6729b9437f3a3a6b4b93407ab4897d67b 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -66,6 +66,7 @@ class Settings::PreferencesController < Settings::BaseController
       :setting_show_quote_button,
       :setting_show_bookmark_button,
       :setting_show_target,
+      :setting_strip_formatting,
       notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
       interactions: %i(must_be_follower must_be_following must_be_following_dm)
     )
diff --git a/app/helpers/statuses_helper.rb b/app/helpers/statuses_helper.rb
index adb7918c53fd14b867d5b958744f0c4173f17cc3..694cdff6c197a31d33022c401c157d674d74eeb0 100644
--- a/app/helpers/statuses_helper.rb
+++ b/app/helpers/statuses_helper.rb
@@ -61,6 +61,17 @@ module StatusesHelper
     embedded_view? ? '_blank' : nil
   end
 
+  def text_formatting_classes
+    case current_user&.setting_strip_formatting
+    when 'none', nil
+      'rich-text rich-blocks'
+    when 'blocks'
+      'rich-text'
+    when 'all'
+      nil
+    end
+  end
+
   def style_classes(status, is_predecessor, is_successor, include_threads)
     classes = ['entry']
     classes << 'entry-predecessor' if is_predecessor
diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js
index 60f8b1c7e09d49ca750c0087392ab3e7ae843db2..5cbfd6c0b5e1956f523250ed51c9203a2828fe79 100644
--- a/app/javascript/mastodon/components/status_content.js
+++ b/app/javascript/mastodon/components/status_content.js
@@ -8,6 +8,7 @@ import classnames from 'classnames';
 import PollContainer from 'mastodon/containers/poll_container';
 import Icon from 'mastodon/components/icon';
 import { autoPlayGif } from 'mastodon/initial_state';
+import { stripFormatting } from 'mastodon/initial_state';
 
 const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
 
@@ -210,6 +211,8 @@ export default class StatusContent extends React.PureComponent {
       'status__content--with-action': this.props.onClick && this.context.router,
       'status__content--with-spoiler': status.get('spoiler_text').length > 0,
       'status__content--collapsed': renderReadMore,
+      'rich-text': stripFormatting !== 'all',
+      'rich-blocks': stripFormatting === 'none',
     });
 
     if (isRtl(status.get('search_index'))) {
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index 289c02148334a7343fe09728f3104e6500047381..487e09e0a93861237b814996966da044a5b792d0 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -35,5 +35,6 @@ export const show_navigation_panel = getMeta('show_navigation_panel');
 export const show_quote_button = getMeta('show_quote_button');
 export const show_bookmark_button = getMeta('show_bookmark_button');
 export const show_target = getMeta('show_target');
+export const stripFormatting = getMeta('strip_formatting');
 
 export default initialState;
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 5e0c090f516fb1f9f78d144d3ad5d322c7db200c..5e28b0961cd1ef7e5b4264ee20013587d97caf07 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -843,10 +843,6 @@
 
   &.status__content--with-spoiler {
     white-space: normal;
-
-    .status__content__text {
-      white-space: pre-wrap;
-    }
   }
 
   .emojione {
@@ -855,7 +851,9 @@
     margin: -3px 0 0;
   }
 
-  p {
+  p,
+  pre,
+  blockquote {
     margin-bottom: 20px;
     white-space: pre-wrap;
 
@@ -864,6 +862,175 @@
     }
   }
 
+  h1,
+  h2,
+  h3,
+  h4,
+  h5 {
+    margin-bottom: 20px;
+  }
+
+  blockquote {
+    white-space: normal;
+
+    p:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  ul,
+  ol {
+    p {
+      margin-bottom: 0;
+    }
+  }
+
+  &:not(.rich-text) {
+    del {
+      text-decoration: none;
+
+      &::before,
+      &::after {
+        content: '~~';
+      }
+    }
+
+    code {
+      font-family: inherit;
+    }
+
+    u {
+      text-decoration: none;
+
+      &::before,
+      &::after {
+        content: '__';
+      }
+    }
+
+    h1::before {
+      content: '# ';
+    }
+
+    h2::before {
+      content: '## ';
+    }
+
+    h3::before {
+      content: '### ';
+    }
+
+    h4::before {
+      content: '#### ';
+    }
+
+    h5::before {
+      content: '##### ';
+    }
+
+    b,
+    strong {
+      &::before,
+      &::after {
+        content: '**';
+      }
+    }
+
+    em,
+    i {
+      &::before,
+      &::after {
+        content: '*';
+      }
+    }
+  }
+
+  &:not(.rich-blocks) {
+    blockquote {
+      position: relative;
+      padding-left: 1em;
+      overflow: hidden;
+    }
+
+    blockquote::before {
+      position: absolute;
+      content: '>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a>\a';
+      white-space: pre-wrap;
+      left: 0;
+      top: 0;
+    }
+
+    li::before {
+      position: absolute;
+      content: '*';
+      left: 0;
+      top: 0;
+    }
+
+    li {
+      position: relative;
+      padding-left: 1em;
+    }
+  }
+
+  &.rich-text {
+    h1,
+    h2 {
+      font-weight: 700;
+    }
+
+    h3,
+    h4,
+    h5 {
+      font-weight: 500;
+    }
+
+    b,
+    strong {
+      font-weight: 700;
+    }
+
+    em,
+    i {
+      font-style: italic;
+    }
+
+    sub {
+      font-size: smaller;
+      text-align: sub;
+    }
+  }
+
+  &.rich-blocks {
+    h1,
+    h2 {
+      font-size: 18px;
+    }
+
+    h2 {
+      font-size: 16px;
+    }
+
+    blockquote {
+      padding-left: 10px;
+      border-left: 3px solid $darker-text-color;
+      color: $darker-text-color;
+    }
+
+    ul,
+    ol {
+      margin-left: 1em;
+    }
+
+    ul {
+      list-style-type: disc;
+    }
+
+    ol {
+      list-style-type: decimal;
+    }
+  }
+
   a {
     color: $secondary-text-color;
     text-decoration: none;
diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb
index 04929d311557f089bd01f1d3c742f65ae0439047..545a53d518d261dacbcb336840830ef68628d8f1 100644
--- a/app/lib/sanitize_config.rb
+++ b/app/lib/sanitize_config.rb
@@ -72,11 +72,13 @@ class Sanitize
     end
 
     MASTODON_STRICT ||= freeze_config(
-      elements: %w(p br span a),
+      elements: %w(p br span a abbr del pre blockquote code b strong u sub i em h1 h2 h3 h4 h5 ul ol li),
 
       attributes: {
-        'a'    => %w(href rel class),
-        'span' => %w(class),
+        'a'          => %w(href rel class title),
+        'span'       => %w(class),
+        'abbr'       => %w(title),
+        'blockquote' => %w(cite),
       },
 
       add_attributes: {
@@ -86,7 +88,10 @@ class Sanitize
         },
       },
 
-      protocols: {},
+      protocols: {
+        'a'          => { 'href' => HTTP_PROTOCOLS },
+        'blockquote' => { 'cite' => HTTP_PROTOCOLS },
+      },
 
       transformers: [
         CLASS_WHITELIST_TRANSFORMER,
diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb
index de5c639feccf6dd65fe4d111776a0a489a30bf5d..845f684fa252cc440afaa959a4d0e35705d01d79 100644
--- a/app/lib/user_settings_decorator.rb
+++ b/app/lib/user_settings_decorator.rb
@@ -50,6 +50,7 @@ class UserSettingsDecorator
     user.settings['show_quote_button']                 = show_quote_button_preference if change?('setting_show_quote_button')
     user.settings['show_bookmark_button']              = show_bookmark_button_preference if change?('setting_show_bookmark_button')
     user.settings['show_target']                       = show_target_preference if change?('setting_show_target')
+    user.settings['strip_formatting']    = strip_formatting_preference if change?('setting_strip_formatting')
   end
 
   def merged_notification_emails
@@ -71,7 +72,7 @@ class UserSettingsDecorator
   def default_federation_preference
     boolean_cast_setting 'setting_default_federation'
   end
-  
+
   def default_content_type_preference
     settings['setting_default_content_type']
   end
@@ -192,6 +193,10 @@ class UserSettingsDecorator
     boolean_cast_setting 'setting_show_target'
   end
 
+  def strip_formatting_preference
+    settings['setting_strip_formatting']
+  end
+
   def boolean_cast_setting(key)
     ActiveModel::Type::Boolean.new.cast(settings[key])
   end
diff --git a/app/models/user.rb b/app/models/user.rb
index 83a617f3c82d629e0fe726f9b6697df8a139b91d..13770c35e6ac30593db8f7390df12e5ce50ded89 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -120,7 +120,7 @@ class User < ApplicationRecord
            :show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_target,
            :show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_followed_by, :show_target,
            :follow_button_to_list_adder, :show_navigation_panel, :show_quote_button, :show_bookmark_button,
-           to: :settings, prefix: :setting, allow_nil: false
+           :strip_formatting, to: :settings, prefix: :setting, allow_nil: false
 
   attr_reader :invite_code, :sign_in_token_attempt
   attr_writer :external
diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb
index b6390c23234a958af82b8e04310b972aa3c89a15..afdd2db2ae749840b5d1f687d4944f3d751ab98a 100644
--- a/app/serializers/initial_state_serializer.rb
+++ b/app/serializers/initial_state_serializer.rb
@@ -43,6 +43,7 @@ class InitialStateSerializer < ActiveModel::Serializer
       store[:use_blurhash]                      = object.current_account.user.setting_use_blurhash
       store[:use_pending_items]                 = object.current_account.user.setting_use_pending_items
       store[:is_staff]                          = object.current_account.user.staff?
+      store[:strip_formatting]                  = object.current_account.user.setting_strip_formatting
       store[:trends]                            = Setting.trends && object.current_account.user.setting_trends
       store[:crop_images]                       = object.current_account.user.setting_crop_images
       store[:show_follow_button_on_timeline]    = object.current_account.user.setting_show_follow_button_on_timeline
diff --git a/app/serializers/rest/preferences_serializer.rb b/app/serializers/rest/preferences_serializer.rb
index 119f0e06d89a5831ea7702478bdb8a05b2934194..52daf37caadc922d5add7dac8c228f5a07f7db3d 100644
--- a/app/serializers/rest/preferences_serializer.rb
+++ b/app/serializers/rest/preferences_serializer.rb
@@ -7,6 +7,7 @@ class REST::PreferencesSerializer < ActiveModel::Serializer
 
   attribute :reading_default_sensitive_media, key: 'reading:expand:media'
   attribute :reading_default_sensitive_text, key: 'reading:expand:spoilers'
+  attribute :reading_strip_formatting, key: 'reading:formatting:strip'
 
   def posting_default_privacy
     object.user.setting_default_privacy
@@ -27,4 +28,8 @@ class REST::PreferencesSerializer < ActiveModel::Serializer
   def reading_default_sensitive_text
     object.user.setting_expand_spoilers
   end
+
+  def reading_strip_formatting
+    object.user.setting_strip_formatting
+  end
 end
diff --git a/app/views/settings/preferences/other/show.html.haml b/app/views/settings/preferences/other/show.html.haml
index 91baca1b4068e0006e2129693240e475ea93eebc..4eb682d629c610765d7318db8c5a5fdc7e630e63 100644
--- a/app/views/settings/preferences/other/show.html.haml
+++ b/app/views/settings/preferences/other/show.html.haml
@@ -61,6 +61,9 @@
   .fields-group
     = f.input :setting_show_bookmark_button, as: :boolean, wrapper: :with_label
 
+  .fields-group
+    = f.input :setting_strip_formatting, collection: ['none', 'blocks', 'all'], wrapper: :with_floating_label, include_blank: false, label_method: lambda { |value| safe_join([I18n.t("statuses.strip_formatting.#{value}"), content_tag(:span, I18n.t("statuses.strip_formatting.#{value}_long"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', hint: false
+
   -# .fields-group
   -#   = f.input :setting_show_target, as: :boolean, wrapper: :with_label
 
diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml
index e27e84da84f74b28573ab1370a01617d5d3c74b3..d5ae1f01bfba16ddcc485fcdfb0465cb5f52bd79 100644
--- a/app/views/statuses/_detailed_status.html.haml
+++ b/app/views/statuses/_detailed_status.html.haml
@@ -15,7 +15,7 @@
 
   = account_action_button(status.account)
 
-  .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
+  .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?), class: text_formatting_classes }<
     - if status.spoiler_text?
       %p<
         %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}&nbsp;
diff --git a/app/views/statuses/_quote_status.html.haml b/app/views/statuses/_quote_status.html.haml
index 373eff5aa2c9a7b159313b2e346731bb1cc0fa17..fa3c759f2d55736ce82e7cb918cdcc1003605ba5 100644
--- a/app/views/statuses/_quote_status.html.haml
+++ b/app/views/statuses/_quote_status.html.haml
@@ -11,14 +11,14 @@
         = acct(status.account)
         = fa_icon('lock') if status.account.locked?
 
-  .status__content.emojify<
+  .status__content.emojify{ class: text_formatting_classes }<
     - if status.spoiler_text?
       %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<
         %span.p-summary> #{Formatter.instance.format_spoiler(status)}&nbsp;
         %button.status__content__spoiler-link= t('statuses.show_more')
     .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }
       = Formatter.instance.format_in_quote(status, custom_emojify: true)
-  
+
   - if !status.media_attachments.empty?
     - if status.media_attachments.first.video?
       - video = status.media_attachments.first
diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml
index c83a8bad03ec747ed98f3cb74e75367a5da3315d..17777eea1e0ab949545d157a211f7fa5ef6effac 100644
--- a/app/views/statuses/_simple_status.html.haml
+++ b/app/views/statuses/_simple_status.html.haml
@@ -21,7 +21,7 @@
           %span.display-name__account
             = acct(status.account)
             = fa_icon('lock') if status.account.locked?
-  .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
+  .status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?), class: text_formatting_classes }<
     - if status.spoiler_text?
       %p<
         %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}&nbsp;
diff --git a/config/locales/en.yml b/config/locales/en.yml
index b98283c1944e2a3fa6fb70ead648ddf0eb943dda..adb962cc907389002acbb965a9f67f4db7b239db 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1302,6 +1302,13 @@ en:
     show_more: Show more
     show_thread: Show thread
     sign_in_to_participate: Sign in to participate in the conversation
+    strip_formatting:
+      all: All
+      all_long: Strip all advanced formatting
+      blocks: Block elements
+      blocks_long: Strip formatting for title headers and block quotes
+      none: None
+      none_long: Do not strip any formatting supported by Mastodon
     title: '%{name}: "%{quote}"'
     visibilities:
       direct: Direct
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 4bff199bc5ad4b9550cdc20a671e95707613943a..49f57b74706892e8fd58a3021aa8c44506537eea 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -187,6 +187,7 @@ en:
         setting_show_subscribe_button_on_timeline: Show subscribe button on timeline
         setting_show_followed_by: Reflect the following status on the follow button
         setting_show_target: Enable targeting features
+        setting_strip_formatting: Strip advanced formatting from toots
         setting_system_font_ui: Use system's default font
         setting_theme: Site theme
         setting_trends: Show today's trends
diff --git a/config/settings.yml b/config/settings.yml
index a044caf06723b4b8053d32deab7a22d3f6060152..a1b0d06e63dd66dc20c38c517f4f6f786dc526da 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -35,7 +35,6 @@ defaults: &defaults
   noindex: false
   theme: 'default'
   aggregate_reblogs: true
-  advanced_layout: false
   use_blurhash: true
   use_pending_items: false
   trends: true