diff --git a/themes/bs_bootstrap/css/components/forms.css b/themes/bs_bootstrap/css/components/forms.css
index 7a82264..c748c01 100644
--- a/themes/bs_bootstrap/css/components/forms.css
+++ b/themes/bs_bootstrap/css/components/forms.css
@@ -265,13 +265,222 @@ select.form-control-lg:not([size]):not([multiple]) {
   width: 100%;
 }
 
+.custom-control {
+  position: relative;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  min-height: 1.5rem;
+  padding-left: 1.5rem;
+  margin-right: 1rem;
+  cursor: pointer;
+}
+
+.custom-control-input {
+  position: absolute;
+  z-index: -1;
+  opacity: 0;
+}
+
+.custom-control-input:checked ~ .custom-control-indicator {
+  color: #fff;
+  background-color: #0275d8;
+}
+
+.custom-control-input:focus ~ .custom-control-indicator {
+  box-shadow: 0 0 0 1px #fff, 0 0 0 3px #0275d8;
+}
+
+.custom-control-input:active ~ .custom-control-indicator {
+  color: #fff;
+  background-color: #8fcafe;
+}
+
+.custom-control-input:disabled ~ .custom-control-indicator {
+  cursor: not-allowed;
+  background-color: #eceeef;
+}
+
+.custom-control-input:disabled ~ .custom-control-description {
+  color: #636c72;
+  cursor: not-allowed;
+}
+
+.custom-control-indicator {
+  position: absolute;
+  top: 0.25rem;
+  left: 0;
+  display: block;
+  width: 1rem;
+  height: 1rem;
+  pointer-events: none;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  background-color: #ddd;
+  background-repeat: no-repeat;
+  background-position: center center;
+  background-size: 50% 50%;
+}
+
+.custom-checkbox .custom-control-indicator {
+  border-radius: 0.25rem;
+}
+
+.custom-checkbox .custom-control-input:checked ~ .custom-control-indicator {
+  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
+}
+
+.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-indicator {
+  background-color: #0275d8;
+  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E");
+}
+
+.custom-radio .custom-control-indicator {
+  border-radius: 50%;
+}
+
+.custom-radio .custom-control-input:checked ~ .custom-control-indicator {
+  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E");
+}
+
+.custom-controls-stacked {
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-flex-direction: column;
+      -ms-flex-direction: column;
+          flex-direction: column;
+}
+
+.custom-controls-stacked .custom-control {
+  margin-bottom: 0.25rem;
+}
+
+.custom-controls-stacked .custom-control + .custom-control {
+  margin-left: 0;
+}
+
+.custom-select {
+  display: inline-block;
+  max-width: 100%;
+  height: calc(2.25rem + 2px);
+  padding: 0.375rem 1.75rem 0.375rem 0.75rem;
+  line-height: 1.25;
+  color: #464a4c;
+  vertical-align: middle;
+  background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right 0.75rem center;
+  background-size: 8px 10px;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 0.25rem;
+  -moz-appearance: none;
+  -webkit-appearance: none;
+}
+
+.custom-select:focus {
+  border-color: #5cb3fd;
+  outline: none;
+}
+
+.custom-select:focus::-ms-value {
+  color: #464a4c;
+  background-color: #fff;
+}
+
+.custom-select:disabled {
+  color: #636c72;
+  cursor: not-allowed;
+  background-color: #eceeef;
+}
+
+.custom-select::-ms-expand {
+  opacity: 0;
+}
+
+.custom-select-sm {
+  padding-top: 0.375rem;
+  padding-bottom: 0.375rem;
+  font-size: 75%;
+}
+
+.custom-file {
+  position: relative;
+  display: inline-block;
+  max-width: 100%;
+  height: 2.5rem;
+  margin-bottom: 0;
+  cursor: pointer;
+}
+
+.custom-file-input {
+  min-width: 14rem;
+  max-width: 100%;
+  height: 2.5rem;
+  margin: 0;
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+
+.custom-file-control {
+  position: absolute;
+  top: 0;
+  right: 0;
+  left: 0;
+  z-index: 5;
+  height: 2.5rem;
+  padding: 0.5rem 1rem;
+  line-height: 1.5;
+  color: #464a4c;
+  pointer-events: none;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  background-color: #fff;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 0.25rem;
+}
+
+.custom-file-control:lang(en)::after {
+  content: "Choose file...";
+}
+
+.custom-file-control::before {
+  position: absolute;
+  top: -1px;
+  right: -1px;
+  bottom: -1px;
+  z-index: 6;
+  display: block;
+  height: 2.5rem;
+  padding: 0.5rem 1rem;
+  line-height: 1.5;
+  color: #464a4c;
+  background-color: #eceeef;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 0 0.25rem 0.25rem 0;
+}
+
+.custom-file-control:lang(en)::before {
+  content: "Browse";
+}
+
 label {
   margin-bottom: 0.1rem;
 }
 
-.form-actions {
-  margin-top: 1.5rem;
-  margin-bottom: 1.5rem;
+label.form-required:after {
+  content: "*";
+  color: #d9534f;
+}
+
+.custom-file-control::after {
+  content: attr(data-content);
+}
+
+.custom-file-control::before {
+  content: attr(data-browse);
 }
 
 @media (min-width: 576px) {
diff --git a/themes/bs_bootstrap/sass/components/forms.scss b/themes/bs_bootstrap/sass/components/forms.scss
index 029002f..629c030 100644
--- a/themes/bs_bootstrap/sass/components/forms.scss
+++ b/themes/bs_bootstrap/sass/components/forms.scss
@@ -1,11 +1,22 @@
 @import "init";
 @import "bootstrap/scss/forms";
+@import "bootstrap/scss/custom-forms";
 
 label {
   margin-bottom: $spacer-y / 10;
+
+  &.form-required:after {
+    content: "*";
+    color: $brand-danger;
+  }
 }
 
-.form-actions {
-  margin-top: 1.5 * $spacer-y;
-  margin-bottom: 1.5 * $spacer-y;
+.custom-file-control {
+  &::after {
+    content: attr(data-content);
+  }
+
+  &::before {
+    content: attr(data-browse);
+  }
 }
diff --git a/themes/bs_bootstrap/templates/form/input--file.html.twig b/themes/bs_bootstrap/templates/form/input--file.html.twig
new file mode 100644
index 0000000..87bc301
--- /dev/null
+++ b/themes/bs_bootstrap/templates/form/input--file.html.twig
@@ -0,0 +1,10 @@
+{#
+/**
+ * @file
+ * Theme override for file #type form element.
+ */
+#}
+<label class="custom-file">
+  <input{{ attributes.addClass(['form-control', 'custom-file-input']) }} />{{ children }}
+  <span data-content="{{ 'Choose a file...'|t }}" data-browse="{{ 'Browse'|t }}" class="custom-file-control"></span>
+</label>
diff --git a/themes/bs_bootstrap/templates/form/input--radio.html.twig b/themes/bs_bootstrap/templates/form/input--radio.html.twig
new file mode 100644
index 0000000..fb79576
--- /dev/null
+++ b/themes/bs_bootstrap/templates/form/input--radio.html.twig
@@ -0,0 +1,13 @@
+{#
+/**
+ * @file
+ * Theme override for an 'input' #type form element.
+ *
+ * Available variables:
+ * - attributes: A list of HTML attributes for the input element.
+ * - children: Optional additional rendered elements.
+ *
+ * @see template_preprocess_input()
+ */
+#}
+<input{{ attributes.addClass('form-check-input') }} />{{ children }}
