myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lof...@apache.org
Subject [myfaces-tobago] branch master updated: TOBAGO-2058: Use java generics for *Renderer classes
Date Wed, 21 Oct 2020 09:54:57 GMT
This is an automated email from the ASF dual-hosted git repository.

lofwyr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git


The following commit(s) were added to refs/heads/master by this push:
     new d49e4fc  TOBAGO-2058: Use java generics for *Renderer classes
d49e4fc is described below

commit d49e4fcc374613545377790333dda6e1bf3dd57c
Author: Udo Schnurpfeil <udo.schnurpfeil@irian.eu>
AuthorDate: Wed Oct 21 11:54:42 2020 +0200

    TOBAGO-2058: Use java generics for *Renderer classes
    
    Also: remove deprecated <tc:treeCommand> (replaced by <tc:link>
---
 tobago-core/npm/scss/_tobago.scss                  |   6 +-
 .../myfaces/tobago/component/RendererTypes.java    |   2 -
 .../org/apache/myfaces/tobago/component/Tags.java  |   2 -
 .../internal/component/AbstractUITreeCommand.java  |  26 ----
 .../renderer/BadgeInsideButtonsRenderer.java       |   3 +-
 .../internal/renderkit/renderer/BadgeRenderer.java |  18 +--
 .../internal/renderkit/renderer/BarRenderer.java   |  24 ++-
 .../internal/renderkit/renderer/BoxRenderer.java   |  27 ++--
 .../renderer/ButtonInsideButtonsRenderer.java      |   6 +-
 .../renderer/ButtonInsideInAfterRenderer.java      |   8 +-
 .../renderkit/renderer/ButtonInsideInRenderer.java |   6 +-
 .../renderkit/renderer/ButtonRenderer.java         |  11 +-
 .../renderkit/renderer/ButtonsRenderer.java        |  21 ++-
 ...Base.java => CollapsiblePanelRendererBase.java} |  18 +--
 .../renderkit/renderer/CommandRendererBase.java    |  79 +++++-----
 .../internal/renderkit/renderer/DateRenderer.java  |  15 +-
 .../renderer/DecodingCommandRendererBase.java      |  14 +-
 .../renderer/DecodingInputRendererBase.java        |   4 +-
 .../renderkit/renderer/FigureRenderer.java         |  18 +--
 .../internal/renderkit/renderer/FileRenderer.java  |  64 ++++----
 .../renderkit/renderer/FlexLayoutRenderer.java     |  16 +-
 .../renderkit/renderer/FlowLayoutRenderer.java     |  16 +-
 .../renderkit/renderer/FooterRenderer.java         |  18 +--
 .../internal/renderkit/renderer/FormRenderer.java  |  20 +--
 .../renderkit/renderer/GridLayoutRenderer.java     |  18 +--
 .../renderkit/renderer/HeaderRenderer.java         |  18 +--
 .../renderkit/renderer/HiddenRenderer.java         |  16 +-
 .../internal/renderkit/renderer/ImageRenderer.java |  30 ++--
 .../internal/renderkit/renderer/InRenderer.java    |  56 ++++---
 .../renderer/LabelLayoutRendererBase.java          |  35 ++---
 .../internal/renderkit/renderer/LabelRenderer.java |  19 ++-
 .../renderer/LinkInsideCommandRenderer.java        |   6 +-
 .../renderer/LinkInsideLinksRenderer.java          |  10 +-
 .../internal/renderkit/renderer/LinkRenderer.java  |   6 +-
 .../internal/renderkit/renderer/LinksRenderer.java |  15 +-
 .../renderer/MessageLayoutRendererBase.java        |  30 ++--
 .../renderkit/renderer/MessagesRenderer.java       |  25 ++-
 .../renderkit/renderer/MetaLinkRenderer.java       |  20 ++-
 .../internal/renderkit/renderer/MetaRenderer.java  |  16 +-
 .../renderkit/renderer/ObjectRenderer.java         |  25 ++-
 .../renderer/OutInsideBoxLabelRenderer.java        |   7 +-
 .../renderkit/renderer/OutInsideInRenderer.java    |   7 +-
 .../renderer/OutInsideSectionLabelRenderer.java    |   7 +-
 .../internal/renderkit/renderer/OutRenderer.java   |  41 +++--
 .../internal/renderkit/renderer/PageRenderer.java  |  39 +++--
 .../internal/renderkit/renderer/PanelRenderer.java |  26 ++--
 .../internal/renderkit/renderer/PopupRenderer.java |  22 ++-
 .../renderkit/renderer/ProgressRenderer.java       |  25 ++-
 .../internal/renderkit/renderer/RangeRenderer.java |  56 +++----
 .../internal/renderkit/renderer/RowRenderer.java   |   5 +-
 .../renderkit/renderer/ScriptRenderer.java         |  10 +-
 .../renderkit/renderer/SectionRenderer.java        |  29 ++--
 .../renderkit/renderer/SegmentLayoutRenderer.java  |  41 +++--
 ...SelectBooleanCheckboxInsideCommandRenderer.java |   9 +-
 .../renderer/SelectBooleanCheckboxRenderer.java    |  69 ++++-----
 .../SelectManyCheckboxInsideCommandRenderer.java   |   8 +-
 .../renderer/SelectManyCheckboxRenderer.java       |  51 +++----
 .../renderer/SelectManyListboxRenderer.java        |  52 +++----
 .../renderkit/renderer/SelectManyRendererBase.java |  21 ++-
 .../renderer/SelectManyShuttleRenderer.java        |  54 ++++---
 .../renderer/SelectOneChoiceInsideInRenderer.java  |   9 +-
 .../renderer/SelectOneChoiceRenderer.java          |  44 +++---
 .../renderer/SelectOneListboxRenderer.java         |  50 +++---
 .../SelectOneRadioInsideCommandRenderer.java       |   6 +-
 .../renderkit/renderer/SelectOneRadioRenderer.java |  55 +++----
 .../renderkit/renderer/SelectOneRendererBase.java  |  13 +-
 .../renderer/SelectReferenceRenderer.java          |   9 +-
 .../renderer/SeparatorInsideCommandRenderer.java   |  10 +-
 .../renderkit/renderer/SeparatorRenderer.java      |  19 ++-
 .../renderer/SheetPageCommandRenderer.java         |   4 +-
 .../internal/renderkit/renderer/SheetRenderer.java | 170 ++++++++++-----------
 .../renderkit/renderer/SplitLayoutRenderer.java    |  21 ++-
 .../internal/renderkit/renderer/StarsRenderer.java |  47 +++---
 .../internal/renderkit/renderer/StyleRenderer.java |  76 +++++----
 .../renderkit/renderer/SubviewRenderer.java        |  14 +-
 .../renderkit/renderer/SuggestRenderer.java        |  35 ++---
 .../renderkit/renderer/TabGroupRenderer.java       |  34 ++---
 .../renderkit/renderer/TextareaRenderer.java       |  68 ++++-----
 .../renderkit/renderer/TreeCommandRenderer.java    |  30 ----
 .../renderkit/renderer/TreeIconRenderer.java       |  22 ++-
 .../renderkit/renderer/TreeIndentRenderer.java     |  19 ++-
 .../renderkit/renderer/TreeLabelRenderer.java      |  16 +-
 .../renderkit/renderer/TreeListboxRenderer.java    |  30 ++--
 .../renderkit/renderer/TreeNodeRenderer.java       |  53 +++----
 .../internal/renderkit/renderer/TreeRenderer.java  |  53 +++----
 .../renderkit/renderer/TreeSelectRenderer.java     |  47 +++---
 .../renderkit/renderer/VerbatimRenderer.java       |   4 +-
 .../taglib/component/ColumnNodeTagDeclaration.java |   4 +-
 .../component/TreeCommandTagDeclaration.java       |  84 ----------
 .../taglib/component/TreeNodeTagDeclaration.java   |   2 +-
 .../myfaces/tobago/renderkit/RendererBase.java     | 102 +++++++++----
 .../myfaces/tobago/renderkit/css/TobagoClass.java  |   1 -
 .../tobago/example/demo/EventController.java       |   2 -
 .../30-whats-new/60-new-in-5-0/Tobago_5.0.xhtml    |   1 +
 .../090-tree/00-command/Tree_Command_Types.xhtml   |   6 +-
 .../20-component/090-tree/03-menu/Tree_Menu.xhtml  |   4 +-
 .../9010-mode-valueIfSet/Mode_ValueIfSet.xhtml     |  83 +---------
 .../src/main/webapp/navigation.xhtml               |   2 +-
 .../src/main/webapp/script/tobago-test.js          |   9 +-
 .../npm/dist/css/tobago.css                        |  18 +--
 .../npm/dist/css/tobago.css.map                    |   2 +-
 .../npm/dist/css/tobago.min.css                    |   2 +-
 .../npm/dist/css/tobago.min.css.map                |   2 +-
 .../npm/dist/css/tobago.css                        |  18 +--
 .../npm/dist/css/tobago.css.map                    |   2 +-
 .../npm/dist/css/tobago.min.css                    |   2 +-
 .../npm/dist/css/tobago.min.css.map                |   2 +-
 .../npm/dist/css/tobago.css                        |  18 +--
 .../npm/dist/css/tobago.css.map                    |   2 +-
 .../npm/dist/css/tobago.min.css                    |   2 +-
 .../npm/dist/css/tobago.min.css.map                |   2 +-
 .../tobago-theme-speyside/npm/dist/css/tobago.css  |  26 ++--
 .../npm/dist/css/tobago.css.map                    |   2 +-
 .../npm/dist/css/tobago.min.css                    |   2 +-
 .../npm/dist/css/tobago.min.css.map                |   2 +-
 .../npm/scss/_speyside-overwrites.scss             |   6 +-
 .../tobago-theme-standard/npm/dist/css/tobago.css  |  18 +--
 .../npm/dist/css/tobago.css.map                    |   2 +-
 .../npm/dist/css/tobago.min.css                    |   2 +-
 .../npm/dist/css/tobago.min.css.map                |   2 +-
 120 files changed, 1179 insertions(+), 1579 deletions(-)

diff --git a/tobago-core/npm/scss/_tobago.scss b/tobago-core/npm/scss/_tobago.scss
index 31789f0..f22792f 100644
--- a/tobago-core/npm/scss/_tobago.scss
+++ b/tobago-core/npm/scss/_tobago.scss
@@ -393,7 +393,7 @@ h1, h2, h3, h4, h5, h6 {
 }
 
 button {
-  &.tobago-link, &.tobago-treeCommand {
+  &.tobago-link {
     color: $blue;
     border-width: 0;
     padding: 0;
@@ -1546,10 +1546,6 @@ tobago-tab-group {
   margin-right: $spacer * .75 / 2;
 }
 
-.tobago-treeCommand {
-  cursor: pointer;
-}
-
 .tobago-treeNode[data-tobago-level] {
   margin-left: 7rem;
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
index 3d65de6..2e73af9 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
@@ -103,7 +103,6 @@ public enum RendererTypes {
    */
   @Deprecated
   TreeData,
-  TreeCommand,
   TreeIcon,
   TreeIndent,
   TreeLabel,
@@ -190,7 +189,6 @@ public enum RendererTypes {
    */
   @Deprecated
   public static final String TREE_DATA = "TreeData";
-  public static final String TREE_COMMAND = "TreeCommand";
   public static final String TREE_ICON = "TreeIcon";
   public static final String TREE_INDENT = "TreeIndent";
   public static final String TREE_LABEL = "TreeLabel";
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java
index 58bac7b..14e270a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java
@@ -91,7 +91,6 @@ public enum Tags {
   tabGroup,
   toolBar,
   tree,
-  treeCommand,
   treeIcon,
   treeIndent,
   treeLabel,
@@ -163,7 +162,6 @@ public enum Tags {
   public static final String TAB_GROUP = "tabGroup";
   public static final String TOOL_BAR = "toolBar";
   public static final String TREE = "tree";
-  public static final String TREE_COMMAND = "treeCommand";
   public static final String TREE_ICON = "treeIcon";
   public static final String TREE_INDENT = "treeIndent";
   public static final String TREE_LABEL = "treeLabel";
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUITreeCommand.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUITreeCommand.java
deleted file mode 100644
index 22b74fc..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUITreeCommand.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.internal.component;
-
-/**
- * {@link org.apache.myfaces.tobago.internal.taglib.component.TreeCommandTagDeclaration}
- */
-public abstract class AbstractUITreeCommand extends AbstractUICommand {
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeInsideButtonsRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeInsideButtonsRenderer.java
index a2d4549..fda55d1 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeInsideButtonsRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeInsideButtonsRenderer.java
@@ -19,10 +19,11 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
+import org.apache.myfaces.tobago.internal.component.AbstractUIBadge;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
-public class BadgeInsideButtonsRenderer extends BadgeRenderer {
+public class BadgeInsideButtonsRenderer<T extends AbstractUIBadge> extends BadgeRenderer<T> {
 
   @Override
   protected CssItem getAdditionalCssItem() {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeRenderer.java
index 708901a..06cf886 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BadgeRenderer.java
@@ -30,22 +30,20 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class BadgeRenderer extends RendererBase {
+public class BadgeRenderer<T extends AbstractUIBadge> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUIBadge badge = (AbstractUIBadge) component;
-    final Markup markup = badge.getMarkup() != null ? badge.getMarkup() : Markup.NULL;
-    final String tip = badge.getTip();
-    final String value = RenderUtils.currentValue(badge);
+    final Markup markup = component.getMarkup() != null ? component.getMarkup() : Markup.NULL;
+    final String tip = component.getTip();
+    final String value = RenderUtils.currentValue(component);
 
     writer.startElement(HtmlElements.SPAN);
-    writer.writeIdAttribute(badge.getClientId(facesContext));
+    writer.writeIdAttribute(component.getClientId(facesContext));
     writer.writeClassAttribute(
         TobagoClass.BADGE,
         TobagoClass.BADGE.createMarkup(markup),
@@ -53,7 +51,7 @@ public class BadgeRenderer extends RendererBase {
         getBadgeColor(markup),
         markup.contains(Markup.PILL) ? BootstrapClass.ROUNDED_PILL : null,
         getAdditionalCssItem(),
-        badge.getCustomClass());
+        component.getCustomClass());
 
     if (tip != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, tip, true);
@@ -64,7 +62,7 @@ public class BadgeRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
+  public void encodeEndInternal(FacesContext facesContext, T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.SPAN);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BarRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BarRenderer.java
index bba61c7..5dcfffd 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BarRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BarRenderer.java
@@ -42,30 +42,29 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class BarRenderer extends RendererBase {
+public class BarRenderer<T extends AbstractUIBar> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIBar bar = (AbstractUIBar) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String clientId = bar.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final String navbarId = clientId + "::navbar";
-    final Markup markup = bar.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.TOBAGO_BAR);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
         BootstrapClass.NAVBAR,
-        TobagoClass.BAR.createMarkup(bar.getMarkup()),
+        TobagoClass.BAR.createMarkup(component.getMarkup()),
         getNavbarExpand(markup),
         getNavbarColorScheme(markup),
-        bar.getCustomClass());
+        component.getCustomClass());
     writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.NAVIGATION.toString(), false);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, bar);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
-    encodeOpener(facesContext, bar, writer, navbarId);
+    encodeOpener(facesContext, component, writer, navbarId);
 
     writer.startElement(HtmlElements.DIV);
     writer.writeIdAttribute(navbarId);
@@ -107,7 +106,7 @@ public class BarRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
     setRenderTypes(component);
     for (final UIComponent child : component.getChildren()) {
       child.encodeAll(facesContext);
@@ -127,10 +126,9 @@ public class BarRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIBar bar = (AbstractUIBar) component;
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final UIComponent after = ComponentUtils.getFacet(bar, Facets.after);
+    final UIComponent after = ComponentUtils.getFacet(component, Facets.after);
 
     if (after != null) {
       writer.startElement(HtmlElements.DIV);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BoxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BoxRenderer.java
index bc7a271..7053b81 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BoxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/BoxRenderer.java
@@ -37,40 +37,39 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class BoxRenderer extends PanelRendererBase {
+public class BoxRenderer<T extends AbstractUIBox> extends CollapsiblePanelRendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIBox box = (AbstractUIBox) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Markup markup = box.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.DIV);
-    final boolean collapsed = box.isCollapsed();
+    final boolean collapsed = component.isCollapsed();
 
     writer.writeClassAttribute(
         TobagoClass.BOX,
         TobagoClass.BOX.createMarkup(markup),
         BootstrapClass.CARD,
         collapsed ? TobagoClass.COLLAPSED : null,
-        box.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
-    final String clientId = box.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     writer.writeIdAttribute(clientId);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, box);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, box);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
-    if (box.getCollapsedMode() != CollapseMode.none) {
+    if (component.getCollapsedMode() != CollapseMode.none) {
       encodeHidden(writer, clientId, collapsed);
     }
 
-    final UIComponent labelFacet = ComponentUtils.getFacet(box, Facets.label);
-    final String labelString = box.getLabel();
-    final UIComponent bar = ComponentUtils.getFacet(box, Facets.bar);
+    final UIComponent labelFacet = ComponentUtils.getFacet(component, Facets.label);
+    final String labelString = component.getLabel();
+    final UIComponent bar = ComponentUtils.getFacet(component, Facets.bar);
     if (labelFacet != null || labelString != null || bar != null) {
       writer.startElement(HtmlElements.DIV);
       writer.writeClassAttribute(BootstrapClass.CARD_HEADER, TobagoClass.BOX__HEADER);
@@ -99,7 +98,7 @@ public class BoxRenderer extends PanelRendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
     writer.endElement(HtmlElements.DIV);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideButtonsRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideButtonsRenderer.java
index 57c1b2c..42c8799 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideButtonsRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideButtonsRenderer.java
@@ -19,16 +19,16 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
+import org.apache.myfaces.tobago.internal.component.AbstractUIButton;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
 import javax.faces.context.FacesContext;
 
-public class ButtonInsideButtonsRenderer extends ButtonRenderer {
+public class ButtonInsideButtonsRenderer<T extends AbstractUIButton> extends ButtonRenderer<T> {
 
   @Override
-  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final T command) {
     return new CssItem[]{BootstrapClass.BTN_GROUP};
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInAfterRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInAfterRenderer.java
index f8242f3..d39f8c2 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInAfterRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInAfterRenderer.java
@@ -19,21 +19,21 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
+import org.apache.myfaces.tobago.internal.component.AbstractUIButton;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
 import javax.faces.context.FacesContext;
 
-public class ButtonInsideInAfterRenderer extends ButtonInsideInRenderer {
+public class ButtonInsideInAfterRenderer<T extends AbstractUIButton> extends ButtonInsideInRenderer<T> {
 
   @Override
-  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final T command) {
     return new CssItem[]{BootstrapClass.INPUT_GROUP_APPEND};
   }
 
   @Override
-  protected CssItem[] getDropdownCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getDropdownCssItems(final FacesContext facesContext, final T command) {
     return new CssItem[]{BootstrapClass.DROPDOWN_MENU_RIGHT};
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInRenderer.java
index c7c5d04..37efd3b 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonInsideInRenderer.java
@@ -19,16 +19,16 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
+import org.apache.myfaces.tobago.internal.component.AbstractUIButton;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
 import javax.faces.context.FacesContext;
 
-public class ButtonInsideInRenderer extends ButtonRenderer {
+public class ButtonInsideInRenderer<T extends AbstractUIButton> extends ButtonRenderer<T> {
 
   @Override
-  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final T command) {
     return new CssItem[]{BootstrapClass.INPUT_GROUP_PREPEND};
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonRenderer.java
index ed88683..67163b9 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonRenderer.java
@@ -23,7 +23,6 @@ import org.apache.myfaces.tobago.component.Attributes;
 import org.apache.myfaces.tobago.context.Markup;
 import org.apache.myfaces.tobago.internal.component.AbstractUIBadge;
 import org.apache.myfaces.tobago.internal.component.AbstractUIButton;
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
@@ -33,7 +32,7 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class ButtonRenderer extends CommandRendererBase {
+public class ButtonRenderer<T extends AbstractUIButton> extends CommandRendererBase<T> {
 
   @Override
   protected TobagoClass getRendererCssClass() {
@@ -41,7 +40,7 @@ public class ButtonRenderer extends CommandRendererBase {
   }
 
   @Override
-  protected CssItem[] getCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getCssItems(final FacesContext facesContext, final T command) {
     final boolean defaultCommand = ComponentUtils.getBooleanAttribute(command, Attributes.defaultCommand);
     final Markup markup = command.getMarkup() != null ? command.getMarkup() : Markup.NULL;
 
@@ -95,10 +94,8 @@ public class ButtonRenderer extends CommandRendererBase {
   }
 
   @Override
-  protected void encodeBadge(FacesContext facesContext, AbstractUICommand command) throws IOException {
-    final AbstractUIButton button = (AbstractUIButton) command;
-
-    for (final UIComponent child : button.getChildren()) {
+  protected void encodeBadge(FacesContext facesContext, T component) throws IOException {
+    for (final UIComponent child : component.getChildren()) {
       if (child instanceof AbstractUIBadge) {
         child.encodeAll(facesContext);
       }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonsRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonsRenderer.java
index 4d1ad08..ca5fc40 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonsRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ButtonsRenderer.java
@@ -38,27 +38,26 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class ButtonsRenderer extends RendererBase {
+public class ButtonsRenderer<T extends AbstractUIButtons> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIButtons buttons = (AbstractUIButtons) component;
-    final Markup markup = buttons.getMarkup();
+    final Markup markup = component.getMarkup();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.DIV);
-    writer.writeIdAttribute(buttons.getClientId(facesContext));
+    writer.writeIdAttribute(component.getClientId(facesContext));
 
     writer.writeClassAttribute(
         TobagoClass.BUTTONS,
         TobagoClass.BUTTONS.createMarkup(markup),
-        Orientation.vertical.equals(buttons.getOrientation())
+        Orientation.vertical.equals(component.getOrientation())
             ? BootstrapClass.BTN_GROUP_VERTICAL : BootstrapClass.BTN_GROUP,
-        buttons.getCustomClass());
+        component.getCustomClass());
     writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.GROUP.toString(), false);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, buttons);
-    final String tip = buttons.getTip();
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+    final String tip = component.getTip();
     if (tip != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, tip, true);
     }
@@ -70,7 +69,7 @@ public class ButtonsRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
     for (final UIComponent child : component.getChildren()) {
       if (child.isRendered()) {
         if (child instanceof AbstractUIButton) {
@@ -87,7 +86,7 @@ public class ButtonsRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CollapsiblePanelRendererBase.java
similarity index 78%
rename from tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRendererBase.java
rename to tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CollapsiblePanelRendererBase.java
index 7020b7e..ae3aae8 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CollapsiblePanelRendererBase.java
@@ -28,28 +28,26 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.util.Map;
 
-public class PanelRendererBase extends RendererBase {
+public class CollapsiblePanelRendererBase<T extends AbstractUICollapsiblePanel> extends RendererBase<T> {
 
   private static final String SUFFIX_COLLAPSE = "collapse";
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
-    super.decode(facesContext, component);
+  public void decodeInternal(final FacesContext facesContext, final T component) {
+    super.decodeInternal(facesContext, component);
 
-    final AbstractUICollapsiblePanel collapsible = (AbstractUICollapsiblePanel) component;
-    final String clientId = collapsible.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final String hiddenId = clientId + ComponentUtils.SUB_SEPARATOR + SUFFIX_COLLAPSE;
 
     final Map<String, String> requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
     if (requestParameterMap.containsKey(hiddenId)) {
       final String newValue = requestParameterMap.get(hiddenId);
       if (StringUtils.isNotBlank(newValue)) {
-        collapsible.setSubmittedCollapsed(Boolean.valueOf(newValue));
+        component.setSubmittedCollapsed(Boolean.valueOf(newValue));
       }
     }
   }
@@ -71,9 +69,9 @@ public class PanelRendererBase extends RendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
-    if (((AbstractUICollapsiblePanel) component).isNormalLifecycle()) {
-      super.encodeChildren(facesContext, component);
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
+    if (component.isNormalLifecycle()) {
+      super.encodeChildrenInternal(facesContext, component);
     }
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
index a4cbafb..7b69c2b 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
@@ -55,25 +55,24 @@ import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.List;
 
-public abstract class CommandRendererBase extends DecodingCommandRendererBase {
+public abstract class CommandRendererBase<T extends AbstractUICommand> extends DecodingCommandRendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-
-    final AbstractUICommand command = (AbstractUICommand) component;
-    final String clientId = command.getClientId(facesContext);
-    final boolean disabled = command.isDisabled();
-    final LabelWithAccessKey label = new LabelWithAccessKey(command);
-    final boolean anchor = (command.getLink() != null || command.getOutcome() != null) && !disabled;
-    final String target = command.getTarget();
-    final boolean parentOfCommands = command.isParentOfCommands();
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
+
+    final String clientId = component.getClientId(facesContext);
+    final boolean disabled = component.isDisabled();
+    final LabelWithAccessKey label = new LabelWithAccessKey(component);
+    final boolean anchor = (component.getLink() != null || component.getOutcome() != null) && !disabled;
+    final String target = component.getTarget();
+    final boolean parentOfCommands = component.isParentOfCommands();
     final boolean dropdownSubmenu = this instanceof LinkInsideCommandRenderer;
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    encodeBeginOuter(facesContext, command);
+    encodeBeginOuter(facesContext, component);
 
     if (anchor) {
       writer.startElement(HtmlElements.A);
@@ -81,17 +80,17 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
       writer.startElement(HtmlElements.BUTTON);
       writer.writeAttribute(HtmlAttributes.TYPE, HtmlButtonTypes.BUTTON);
     }
-    writer.writeIdAttribute(command.getFieldId(facesContext));
+    writer.writeIdAttribute(component.getFieldId(facesContext));
     writer.writeNameAttribute(clientId);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
 
     if (!disabled) {
       if (anchor) {
-        final String href = RenderUtils.generateUrl(facesContext, command);
+        final String href = RenderUtils.generateUrl(facesContext, component);
         writer.writeAttribute(HtmlAttributes.HREF, href, true);
         writer.writeAttribute(HtmlAttributes.TARGET, target, true);
 
-        command.setOmit(true);
+        component.setOmit(true);
       }
 
       if (label.getAccessKey() != null) {
@@ -99,33 +98,33 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
         AccessKeyLogger.addAccessKey(facesContext, label.getAccessKey(), clientId);
       }
 
-      final int tabIndex = ComponentUtils.getIntAttribute(command, Attributes.tabIndex);
+      final int tabIndex = ComponentUtils.getIntAttribute(component, Attributes.tabIndex);
       if (tabIndex != 0) {
         writer.writeAttribute(HtmlAttributes.TABINDEX, tabIndex);
       }
     }
 
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, command);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     if (parentOfCommands) {
       writer.writeAttribute(DataAttributes.TOGGLE, "dropdown", false);
     }
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, command);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
 
     writer.writeClassAttribute(
         getRendererCssClass(),
-        getRendererCssClass().createMarkup(command.getMarkup()),
-        parentOfCommands ? null : getOuterCssItems(facesContext, command),
-        getCssItems(facesContext, command),
+        getRendererCssClass().createMarkup(component.getMarkup()),
+        parentOfCommands ? null : getOuterCssItems(facesContext, component),
+        getCssItems(facesContext, component),
         parentOfCommands && !dropdownSubmenu ? BootstrapClass.DROPDOWN_TOGGLE : null,
-        command.getCustomClass());
+        component.getCustomClass());
 
-    final boolean defaultCommand = ComponentUtils.getBooleanAttribute(command, Attributes.defaultCommand);
+    final boolean defaultCommand = ComponentUtils.getBooleanAttribute(component, Attributes.defaultCommand);
     if (defaultCommand) {
-      final AbstractUIFormBase form = ComponentUtils.findAncestor(command, AbstractUIFormBase.class);
+      final AbstractUIFormBase form = ComponentUtils.findAncestor(component, AbstractUIFormBase.class);
       if (form != null) {
         writer.writeAttribute(DataAttributes.DEFAULT, form.getClientId(facesContext), false);
       } else {
@@ -134,17 +133,17 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
     }
 
     if (!disabled) {
-      encodeBehavior(writer, facesContext, command);
+      encodeBehavior(writer, facesContext, component);
     }
 
-    final String image = ComponentUtils.getStringAttribute(command, Attributes.image);
+    final String image = ComponentUtils.getStringAttribute(component, Attributes.image);
     HtmlRendererUtils.encodeIconOrImage(writer, image);
 
     if (label.getLabel() != null) {
       writer.startElement(HtmlElements.SPAN);
       HtmlRendererUtils.writeLabelWithAccessKey(writer, label);
       writer.endElement(HtmlElements.SPAN);
-      encodeBadge(facesContext, command);
+      encodeBadge(facesContext, component);
     }
 
     if (anchor) {
@@ -160,9 +159,8 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUICommand command = (AbstractUICommand) component;
-    final boolean parentOfCommands = command.isParentOfCommands();
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
+    final boolean parentOfCommands = component.isParentOfCommands();
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
@@ -172,9 +170,9 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
       writer.startElement(HtmlElements.DIV);
       writer.writeClassAttribute(
           BootstrapClass.DROPDOWN_MENU,
-          getDropdownCssItems(facesContext, command));
-      writer.writeAttribute(Arias.LABELLEDBY, command.getFieldId(facesContext), false);
-      writer.writeAttribute(HtmlAttributes.NAME, command.getClientId(facesContext), false);
+          getDropdownCssItems(facesContext, component));
+      writer.writeAttribute(Arias.LABELLEDBY, component.getFieldId(facesContext), false);
+      writer.writeAttribute(HtmlAttributes.NAME, component.getClientId(facesContext), false);
 
       for (final UIComponent child : component.getChildren()) {
         if (child.isRendered()
@@ -225,12 +223,11 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUICommand command = (AbstractUICommand) component;
-    encodeEndOuter(facesContext, command);
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
+    encodeEndOuter(facesContext, component);
   }
 
-  protected void encodeBeginOuter(final FacesContext facesContext, final AbstractUICommand command) throws IOException {
+  protected void encodeBeginOuter(final FacesContext facesContext, final T command) throws IOException {
     final String clientId = command.getClientId(facesContext);
     final boolean parentOfCommands = command.isParentOfCommands();
     final boolean dropdownSubmenu = this instanceof LinkInsideCommandRenderer;
@@ -248,27 +245,27 @@ public abstract class CommandRendererBase extends DecodingCommandRendererBase {
     }
   }
 
-  protected void encodeEndOuter(final FacesContext facesContext, final AbstractUICommand command) throws IOException {
+  protected void encodeEndOuter(final FacesContext facesContext, final T command) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     if (command.isParentOfCommands()) {
       writer.endElement(HtmlElements.TOBAGO_DROPDOWN);
     }
   }
 
-  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final T command) {
     return null;
   }
 
   abstract TobagoClass getRendererCssClass();
 
-  protected CssItem[] getCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getCssItems(final FacesContext facesContext, final T command) {
     return null;
   }
 
-  protected CssItem[] getDropdownCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getDropdownCssItems(final FacesContext facesContext, final T command) {
     return null;
   }
 
-  protected void encodeBadge(final FacesContext facesContext, final AbstractUICommand command) throws IOException {
+  protected void encodeBadge(final FacesContext facesContext, final T command) throws IOException {
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
index 4f4e7c6..1883f6a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
@@ -38,14 +38,13 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
-public class DateRenderer extends InRenderer {
+public class DateRenderer<T extends AbstractUIDate> extends InRenderer<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -71,8 +70,7 @@ public class DateRenderer extends InRenderer {
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIDate date = (AbstractUIDate) component;
+  protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.DIV);
@@ -85,12 +83,11 @@ public class DateRenderer extends InRenderer {
   }
 
   @Override
-  public void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
 
     super.encodeEndField(facesContext, component);
 
-    final AbstractUIDate date = (AbstractUIDate) component;
-    final String pattern = date.getPattern();
+    final String pattern = component.getPattern();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.SPAN);
@@ -103,8 +100,8 @@ public class DateRenderer extends InRenderer {
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlButtonTypes.BUTTON);
     writer.writeAttribute(HtmlAttributes.TITLE,
         ResourceUtils.getString(facesContext, "date.title"), true);
-    writer.writeAttribute(HtmlAttributes.DISABLED, date.isDisabled() || date.isReadonly());
-    writer.writeAttribute(HtmlAttributes.TABINDEX, date.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.DISABLED, component.isDisabled() || component.isReadonly());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
 
     final boolean hasDate = StringUtils.containsAny(pattern, "yYMDdE");
     final boolean hasTime = StringUtils.containsAny(pattern, "Hhms");
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingCommandRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingCommandRendererBase.java
index f5e9144..92366c5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingCommandRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingCommandRendererBase.java
@@ -19,22 +19,22 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
+import org.apache.myfaces.tobago.internal.component.AbstractUICommandBase;
 import org.apache.myfaces.tobago.renderkit.RendererBase;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.ActionEvent;
 import java.lang.invoke.MethodHandles;
 
-public abstract class DecodingCommandRendererBase extends RendererBase {
+public abstract class DecodingCommandRendererBase<T extends AbstractUICommandBase> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
 
     if (ComponentUtils.isOutputOnly(component)) {
       return;
@@ -42,12 +42,12 @@ public abstract class DecodingCommandRendererBase extends RendererBase {
     final String sourceId = facesContext.getExternalContext().getRequestParameterMap().get("javax.faces.source");
     final String clientId = component.getClientId(facesContext);
     if (LOG.isDebugEnabled()) {
-      LOG.debug("sourceId = '" + sourceId + "'");
-      LOG.debug("clientId = '" + clientId + "'");
+      LOG.debug("sourceId = '{}", sourceId);
+      LOG.debug("clientId = '{}'", clientId);
     }
     if (clientId.equals(sourceId)) {
       if (LOG.isDebugEnabled()) {
-        LOG.debug("queueEvent = '" + clientId + "'");
+        LOG.debug("queueEvent = '{}'", clientId);
       }
       commandActivated(component);
     }
@@ -56,7 +56,7 @@ public abstract class DecodingCommandRendererBase extends RendererBase {
 
   }
 
-  protected void commandActivated(final UIComponent component) {
+  protected void commandActivated(final T component) {
     component.queueEvent(new ActionEvent(component));
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingInputRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingInputRendererBase.java
index c1e61a7..c1d9131 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingInputRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DecodingInputRendererBase.java
@@ -32,12 +32,12 @@ import javax.faces.context.FacesContext;
 import java.lang.invoke.MethodHandles;
 import java.util.Map;
 
-public abstract class DecodingInputRendererBase extends RendererBase {
+public abstract class DecodingInputRendererBase<T extends UIComponent> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     if (!(component instanceof EditableValueHolder)) {
       return; // no decoding required
     }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FigureRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FigureRenderer.java
index 31ab57f..117dd6b 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FigureRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FigureRenderer.java
@@ -33,20 +33,19 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class FigureRenderer extends RendererBase {
+public class FigureRenderer<T extends AbstractUIFigure> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIFigure figure = (AbstractUIFigure) component;
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.startElement(HtmlElements.FIGURE);
 
     writer.writeClassAttribute(
         TobagoClass.FIGURE,
-        TobagoClass.FIGURE.createMarkup(figure.getMarkup()),
+        TobagoClass.FIGURE.createMarkup(component.getMarkup()),
         BootstrapClass.FIGURE,
-        figure.getCustomClass());
-    final String tip = figure.getTip();
+        component.getCustomClass());
+    final String tip = component.getTip();
     if (tip != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, tip, true);
     }
@@ -56,10 +55,9 @@ public class FigureRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIFigure figure = (AbstractUIFigure) component;
-    final UIComponent label = ComponentUtils.getFacet(figure, Facets.label);
-    final String labelString = figure.getLabel();
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
+    final UIComponent label = ComponentUtils.getFacet(component, Facets.label);
+    final String labelString = component.getLabel();
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FileRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FileRenderer.java
index 6db5ee3..798af8c 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FileRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FileRenderer.java
@@ -37,7 +37,6 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.event.ComponentSystemEvent;
 import javax.faces.event.ComponentSystemEventListener;
@@ -52,7 +51,8 @@ import java.util.ArrayList;
 import java.util.List;
 
 @ListenerFor(systemEventClass = PostAddToViewEvent.class)
-public class FileRenderer extends MessageLayoutRendererBase implements ComponentSystemEventListener {
+public class FileRenderer<T extends AbstractUIFile>
+    extends MessageLayoutRendererBase<T> implements ComponentSystemEventListener {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -72,13 +72,12 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
   }
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
-    final AbstractUIFile file = (AbstractUIFile) component;
-    final boolean multiple = file.isMultiple() && !file.isRequired();
+    final boolean multiple = component.isMultiple() && !component.isRequired();
     final Object request = facesContext.getExternalContext().getRequest();
     if (request instanceof HttpServletRequest) {
       try {
@@ -86,27 +85,27 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
         if (multiple) {
           final List<Part> parts = new ArrayList<>();
           for (final Part part : httpServletRequest.getParts()) {
-            if (file.getClientId(facesContext).equals(part.getName())) {
+            if (component.getClientId(facesContext).equals(part.getName())) {
               LOG.debug("Uploaded file '{}', size={}, type='{}'",
                   part.getSubmittedFileName(), part.getSize(), part.getContentType());
               parts.add(new HttpPartWrapper(part));
             }
-            file.setSubmittedValue(parts.toArray(new Part[0]));
+            component.setSubmittedValue(parts.toArray(new Part[0]));
           }
         } else {
-          final Part part = httpServletRequest.getPart(file.getClientId(facesContext));
+          final Part part = httpServletRequest.getPart(component.getClientId(facesContext));
           final String submittedFileName = part.getSubmittedFileName();
           if (LOG.isDebugEnabled()) {
             LOG.debug("Uploaded file '{}', size={}, type='{}'",
                 submittedFileName, part.getSize(), part.getContentType());
           }
           if (submittedFileName.length() > 0) {
-            file.setSubmittedValue(new HttpPartWrapper(part));
+            component.setSubmittedValue(new HttpPartWrapper(part));
           }
         }
       } catch (final Exception e) {
         LOG.error("", e);
-        file.setValid(false);
+        component.setValid(false);
       }
     } else { // todo: PortletRequest
       LOG.warn("Unsupported request type: " + request.getClass().getName());
@@ -116,9 +115,8 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
   }
 
   @Override
-  protected void encodeAttributes(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIFile file = (AbstractUIFile) component;
-    final String placeholder = file.getPlaceholder();
+  protected void encodeAttributes(final FacesContext facesContext, final T component) throws IOException {
+    final String placeholder = component.getPlaceholder();
     final String multiFormat = ResourceUtils.getString(facesContext, "file.selected");
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
@@ -127,16 +125,15 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-
-    final AbstractUIFile file = (AbstractUIFile) component;
-    final String clientId = file.getClientId(facesContext);
-    final String fieldId = file.getFieldId(facesContext);
-    final String accept = createAcceptFromValidators(file);
-    final boolean multiple = file.isMultiple() && !file.isRequired();
-    final boolean disabled = file.isDisabled();
-    final boolean readonly = file.isReadonly();
-    if (file.isMultiple() && file.isRequired()) {
+  protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
+
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final String accept = createAcceptFromValidators(component);
+    final boolean multiple = component.isMultiple() && !component.isRequired();
+    final boolean disabled = component.isDisabled();
+    final boolean readonly = component.isReadonly();
+    if (component.isMultiple() && component.isRequired()) {
       LOG.warn("Required multiple file upload is not supported."); //TODO TOBAGO-1930
     }
 
@@ -145,10 +142,10 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
     writer.startElement(HtmlElements.DIV);
     writer.writeClassAttribute(
         BootstrapClass.FORM_FILE,
-        TobagoClass.FILE.createMarkup(file.getMarkup()),
-        file.getCustomClass(),
+        TobagoClass.FILE.createMarkup(component.getMarkup()),
+        component.getCustomClass(),
         BootstrapClass.FORM_CONTROL_PLAINTEXT);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, file);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     writer.startElement(HtmlElements.INPUT);
     writer.writeAttribute(HtmlAttributes.MULTIPLE, multiple);
@@ -158,21 +155,21 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
     writer.writeIdAttribute(fieldId);
     writer.writeClassAttribute(
         BootstrapClass.FORM_FILE_INPUT,
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(file)));
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)));
     writer.writeNameAttribute(clientId);
     // readonly seems not making sense in browsers.
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled || readonly);
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
-    writer.writeAttribute(HtmlAttributes.REQUIRED, file.isRequired());
+    writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
     // TODO Focus
     //HtmlRendererUtils.renderFocus(clientId, file.isFocus(), ComponentUtils.isError(file), facesContext, writer);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, file);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
     writer.endElement(HtmlElements.INPUT);
 
-    encodeBehavior(writer, facesContext, file);
+    encodeBehavior(writer, facesContext, component);
 
     writer.startElement(HtmlElements.LABEL);
     writer.writeClassAttribute(BootstrapClass.FORM_FILE_LABEL);
@@ -210,14 +207,13 @@ public class FileRenderer extends MessageLayoutRendererBase implements Component
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUIFile file = (AbstractUIFile) component;
-    return file.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlexLayoutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlexLayoutRenderer.java
index 201db164..e800175 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlexLayoutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlexLayoutRenderer.java
@@ -27,30 +27,28 @@ import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class FlexLayoutRenderer extends RendererBase {
+public class FlexLayoutRenderer<T extends AbstractUIFlexLayout> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIFlexLayout flexLayout = (AbstractUIFlexLayout) component;
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Markup markup = flexLayout.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.DIV);
-    writer.writeIdAttribute(flexLayout.getClientId());
+    writer.writeIdAttribute(component.getClientId());
     writer.writeClassAttribute(
         TobagoClass.FLEX_LAYOUT,
         TobagoClass.FLEX_LAYOUT.createMarkup(markup),
-        flexLayout.isHorizontal() ? BootstrapClass.FLEX_ROW : BootstrapClass.FLEX_COLUMN,
-        BootstrapClass.valueOf(flexLayout.getAlignItems()),
+        component.isHorizontal() ? BootstrapClass.FLEX_ROW : BootstrapClass.FLEX_COLUMN,
+        BootstrapClass.valueOf(component.getAlignItems()),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlowLayoutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlowLayoutRenderer.java
index c981e07..06d5a5c 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlowLayoutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FlowLayoutRenderer.java
@@ -28,31 +28,29 @@ import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class FlowLayoutRenderer extends RendererBase {
+public class FlowLayoutRenderer<T extends AbstractUIFlowLayout> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUIFlowLayout flowLayout = (AbstractUIFlowLayout) component;
-    final Markup markup = flowLayout.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.DIV);
-    writer.writeIdAttribute(flowLayout.getClientId());
-    final TextAlign textAlign = flowLayout.getTextAlign();
+    writer.writeIdAttribute(component.getClientId());
+    final TextAlign textAlign = component.getTextAlign();
     writer.writeClassAttribute(
         TobagoClass.FLOW_LAYOUT,
         TobagoClass.FLOW_LAYOUT.createMarkup(markup),
-        flowLayout.getCustomClass(),
+        component.getCustomClass(),
         textAlign != null ? BootstrapClass.textAlign(textAlign) : null);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FooterRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FooterRenderer.java
index 4dd6cc4..ded7283 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FooterRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FooterRenderer.java
@@ -19,7 +19,6 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.context.Markup;
 import org.apache.myfaces.tobago.internal.component.AbstractUIFooter;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.renderkit.RendererBase;
@@ -29,30 +28,27 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlRoleValues;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class FooterRenderer extends RendererBase {
+public class FooterRenderer<T extends AbstractUIFooter> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUIFooter footer = (AbstractUIFooter) component;
-    final Markup markup = footer.getMarkup();
     writer.startElement(HtmlElements.TOBAGO_FOOTER);
     writer.writeIdAttribute(component.getClientId(facesContext));
 
     writer.writeClassAttribute(
-        footer.isFixed() ? BootstrapClass.FIXED_BOTTOM : null,
-        footer.getCustomClass());
+        component.isFixed() ? BootstrapClass.FIXED_BOTTOM : null,
+        component.getCustomClass());
     writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.CONTENTINFO.toString(), false);
-    writer.writeAttribute(HtmlAttributes.TITLE, footer.getTip(), true);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, footer);
+    writer.writeAttribute(HtmlAttributes.TITLE, component.getTip(), true);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.TOBAGO_FOOTER);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FormRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FormRenderer.java
index c532a48..c931929 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FormRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/FormRenderer.java
@@ -26,35 +26,31 @@ import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class FormRenderer extends RendererBase {
+public class FormRenderer<T extends AbstractUIForm> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIForm form = (AbstractUIForm) component;
-
-    if (!form.isPlain()) {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
+    if (!component.isPlain()) {
       final TobagoResponseWriter writer = getResponseWriter(facesContext);
-      final String clientId = form.getClientId(facesContext);
-      final boolean inline = form.isInline();
+      final String clientId = component.getClientId(facesContext);
+      final boolean inline = component.isInline();
 
       writer.startElement(HtmlElements.DIV);
       writer.writeIdAttribute(clientId);
       writer.writeClassAttribute(
           TobagoClass.FORM,
           inline ? BootstrapClass.D_INLINE : null,
-          form.getCustomClass());
+          component.getCustomClass());
     }
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIForm form = (AbstractUIForm) component;
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    if (!form.isPlain()) {
+    if (!component.isPlain()) {
       final TobagoResponseWriter writer = getResponseWriter(facesContext);
       writer.endElement(HtmlElements.DIV);
     }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/GridLayoutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/GridLayoutRenderer.java
index 32afebb..1f617d5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/GridLayoutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/GridLayoutRenderer.java
@@ -33,28 +33,26 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlRoleValues;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class GridLayoutRenderer extends RendererBase {
+public class GridLayoutRenderer<T extends AbstractUIGridLayout> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIGridLayout gridLayout = (AbstractUIGridLayout) component;
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Markup markup = gridLayout.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.DIV);
     writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.PRESENTATION.toString(), false);
-    writer.writeIdAttribute(gridLayout.getClientId(facesContext));
+    writer.writeIdAttribute(component.getClientId(facesContext));
     writer.writeClassAttribute(
         TobagoClass.GRID_LAYOUT,
         TobagoClass.GRID_LAYOUT.createMarkup(markup),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
 
-    final MeasureList columns = MeasureList.parse(gridLayout.getColumns());
-    final MeasureList rows = MeasureList.parse(gridLayout.getRows());
+    final MeasureList columns = MeasureList.parse(component.getColumns());
+    final MeasureList rows = MeasureList.parse(component.getRows());
 
     final AbstractUIStyle style = (AbstractUIStyle) facesContext.getApplication().createComponent(
         facesContext, Tags.style.componentType(), RendererTypes.Style.name());
@@ -73,11 +71,11 @@ public class GridLayoutRenderer extends RendererBase {
 
     style.setGridTemplateColumns(columns.serialize());
     style.setGridTemplateRows(rows.serialize());
-    gridLayout.getChildren().add(style);
+    component.getChildren().add(style);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.endElement(HtmlElements.DIV);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HeaderRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HeaderRenderer.java
index 5b9ce93..c79915f 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HeaderRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HeaderRenderer.java
@@ -19,7 +19,6 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.context.Markup;
 import org.apache.myfaces.tobago.internal.component.AbstractUIHeader;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.renderkit.RendererBase;
@@ -29,33 +28,30 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlRoleValues;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class HeaderRenderer extends RendererBase {
+public class HeaderRenderer<T extends AbstractUIHeader> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUIHeader header = (AbstractUIHeader) component;
-    final Markup markup = header.getMarkup();
     writer.startElement(HtmlElements.TOBAGO_HEADER);
     writer.writeIdAttribute(component.getClientId(facesContext));
     // TBD: NAVBAR_DARK and BG_DARK should not be the default
     // TBD: how to configure it when it is needed, with customClass, or with markup?
 
     writer.writeClassAttribute(
-        header.isFixed() ? BootstrapClass.STICKY_TOP : null,
-        header.getCustomClass());
+        component.isFixed() ? BootstrapClass.STICKY_TOP : null,
+        component.getCustomClass());
 // TBD: should NAVBAR class be in the LinksRenderer?
     writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.BANNER.toString(), false);
-    writer.writeAttribute(HtmlAttributes.TITLE, header.getTip(), true);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, header);
+    writer.writeAttribute(HtmlAttributes.TITLE, component.getTip(), true);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.TOBAGO_HEADER);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HiddenRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HiddenRenderer.java
index 41cd243..69100e8 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HiddenRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/HiddenRenderer.java
@@ -27,23 +27,21 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class HiddenRenderer extends DecodingInputRendererBase {
+public class HiddenRenderer<T extends AbstractUIHidden> extends DecodingInputRendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIHidden hidden = (AbstractUIHidden) component;
-    final String clientId = hidden.getClientId(facesContext);
-    final String value = RenderUtils.currentValue(hidden);
+    final String clientId = component.getClientId(facesContext);
+    final String value = RenderUtils.currentValue(component);
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.INPUT);
-    if (hidden.isDisabled()) {
+    if (component.isDisabled()) {
       // XXX why text instead of hidden here?
       writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.TEXT);
       writer.writeAttribute(HtmlAttributes.DISABLED, true);
@@ -52,12 +50,12 @@ public class HiddenRenderer extends DecodingInputRendererBase {
     }
     writer.writeNameAttribute(clientId);
     writer.writeIdAttribute(clientId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, hidden);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeAttribute(HtmlAttributes.VALUE, value != null ? value : "", true);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.INPUT);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ImageRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ImageRenderer.java
index 6530eec..948c291 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ImageRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ImageRenderer.java
@@ -31,47 +31,45 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class ImageRenderer extends RendererBase {
+public class ImageRenderer<T extends AbstractUIImage> extends RendererBase<T> {
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final AbstractUIImage image = (AbstractUIImage) component;
-    final String value = image.getUrl();
+    final String value = component.getUrl();
     final boolean fontAwesome = value != null && value.startsWith("fa-");
-    final boolean disabled = image.isDisabled()
-        || (image.getParent() instanceof AbstractUICommandBase
-        && ((AbstractUICommandBase) image.getParent()).isDisabled());
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, image);
-    final Markup markup = image.getMarkup();
+    final boolean disabled = component.isDisabled()
+        || (component.getParent() instanceof AbstractUICommandBase
+        && ((AbstractUICommandBase) component.getParent()).isDisabled());
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final Markup markup = component.getMarkup();
     if (fontAwesome) {
       writer.startElement(HtmlElements.I);
-      writer.writeIdAttribute(image.getClientId(facesContext));
+      writer.writeIdAttribute(component.getClientId(facesContext));
       writer.writeClassAttribute(
           Icons.FA,
           Icons.custom(value),
           disabled ? BootstrapClass.DISABLED : null,
-          image.getCustomClass());
+          component.getCustomClass());
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
       writer.endElement(HtmlElements.I);
     } else {
-      final String alt = image.getAlt();
+      final String alt = component.getAlt();
       writer.startElement(HtmlElements.IMG);
-      writer.writeIdAttribute(image.getClientId(facesContext));
-      HtmlRendererUtils.writeDataAttributes(facesContext, writer, image);
+      writer.writeIdAttribute(component.getClientId(facesContext));
+      HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
       writer.writeAttribute(HtmlAttributes.SRC, value, true);
       writer.writeAttribute(HtmlAttributes.ALT, alt != null ? alt : "", true);
       writer.writeClassAttribute(
           TobagoClass.IMAGE,
           TobagoClass.IMAGE.createMarkup(markup),
           disabled ? BootstrapClass.DISABLED : null,
-          image.getCustomClass());
+          component.getCustomClass());
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
       writer.endElement(HtmlElements.IMG);
     }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
index 9cd6bca..d925ef7 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/InRenderer.java
@@ -50,7 +50,7 @@ import javax.faces.validator.Validator;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 
-public class InRenderer extends MessageLayoutRendererBase {
+public class InRenderer<T extends AbstractUIIn> extends MessageLayoutRendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -60,26 +60,25 @@ public class InRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component)
+  protected void encodeBeginField(final FacesContext facesContext, final T component)
       throws IOException {
-    final AbstractUIIn input = (AbstractUIIn) component;
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, input);
-    final String currentValue = getCurrentValue(facesContext, input);
-    final boolean password = ComponentUtils.getBooleanAttribute(input, Attributes.password);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final String currentValue = getCurrentValue(facesContext, component);
+    final boolean password = ComponentUtils.getBooleanAttribute(component, Attributes.password);
     if (LOG.isDebugEnabled()) {
       LOG.debug("currentValue = '{}'", StringUtils.toConfidentialString(currentValue, password));
     }
     final HtmlInputTypes type = password ? HtmlInputTypes.PASSWORD : HtmlInputTypes.TEXT;
-    final String clientId = input.getClientId(facesContext);
-    final String fieldId = input.getFieldId(facesContext);
-    final boolean readonly = input.isReadonly();
-    final boolean disabled = input.isDisabled();
-    final boolean required = ComponentUtils.getBooleanAttribute(input, Attributes.required);
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final boolean readonly = component.isReadonly();
+    final boolean disabled = component.isDisabled();
+    final boolean required = ComponentUtils.getBooleanAttribute(component, Attributes.required);
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final UIComponent after = ComponentUtils.getFacet(input, Facets.after);
-    final UIComponent before = ComponentUtils.getFacet(input, Facets.before);
+    final UIComponent after = ComponentUtils.getFacet(component, Facets.after);
+    final UIComponent before = ComponentUtils.getFacet(component, Facets.before);
 
     if (after != null || before != null) {
       writer.startElement(HtmlElements.DIV); // Wrapping the field to fix input groups with flexLeft/flexRight
@@ -91,15 +90,15 @@ public class InRenderer extends MessageLayoutRendererBase {
 
     writer.startElement(HtmlElements.INPUT);
 
-    if (input.getAccessKey() != null) {
-      writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(input.getAccessKey()), false);
-      AccessKeyLogger.addAccessKey(facesContext, input.getAccessKey(), clientId);
+    if (component.getAccessKey() != null) {
+      writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(component.getAccessKey()), false);
+      AccessKeyLogger.addAccessKey(facesContext, component.getAccessKey(), clientId);
     }
 
     writer.writeAttribute(HtmlAttributes.TYPE, type);
     writer.writeNameAttribute(clientId);
     writer.writeIdAttribute(fieldId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, input);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     if (currentValue != null && !password) {
       writer.writeAttribute(HtmlAttributes.VALUE, currentValue, true);
     }
@@ -109,7 +108,7 @@ public class InRenderer extends MessageLayoutRendererBase {
     int maxLength = 0;
     int minLength = 0;
     String pattern = null;
-    for (final Validator validator : input.getValidators()) {
+    for (final Validator validator : component.getValidators()) {
       if (validator instanceof LengthValidator) {
         final LengthValidator lengthValidator = (LengthValidator) validator;
         maxLength = lengthValidator.getMaximum();
@@ -130,26 +129,26 @@ public class InRenderer extends MessageLayoutRendererBase {
     }
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, input.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
     if (!disabled && !readonly) {
-      writer.writeAttribute(HtmlAttributes.PLACEHOLDER, input.getPlaceholder(), true);
+      writer.writeAttribute(HtmlAttributes.PLACEHOLDER, component.getPlaceholder(), true);
     }
 
     final CssItem rendererCssClass = getRendererCssClass();
     writer.writeClassAttribute(
         rendererCssClass,
 //        rendererCssClass != null ? rendererCssClass.createMarkup(markup) : null,
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(input)),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
         BootstrapClass.FORM_CONTROL,
-        input.getCustomClass());
+        component.getCustomClass());
 
     writer.writeAttribute(HtmlAttributes.REQUIRED, required);
-    HtmlRendererUtils.renderFocus(clientId, input.isFocus(), ComponentUtils.isError(input), facesContext, writer);
-    writeAdditionalAttributes(facesContext, writer, input);
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
+    writeAdditionalAttributes(facesContext, writer, component);
 
     writer.endElement(HtmlElements.INPUT);
 
-    encodeBehavior(writer, facesContext, input);
+    encodeBehavior(writer, facesContext, component);
 
     encodeGroupAddon(facesContext, writer, after, true);
 
@@ -198,7 +197,7 @@ public class InRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
   }
 
   protected CssItem getRendererCssClass() {
@@ -211,8 +210,7 @@ public class InRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUIInput input = (AbstractUIInput) component;
-    return input.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java
index 2f39e77..eab85be 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java
@@ -44,16 +44,17 @@ import java.util.List;
  * Manages the rendering of the <b>label</b> and the <b>field</b> together with different possibilities for the position
  * of the label (defined by {@link org.apache.myfaces.tobago.component.Attributes#labelLayout}
  */
-public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase {
+public abstract class LabelLayoutRendererBase<T extends UIComponent & SupportsLabelLayout>
+    extends DecodingInputRendererBase<T> {
 
   public abstract HtmlElements getComponentTag();
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
     encodeBeginSurroundingLabel(facesContext, component);
 
-    if (((SupportsLabelLayout) component).isNextToRenderIsLabel()) {
+    if (component.isNextToRenderIsLabel()) {
       // skip, because its only the lable to render
     } else {
       encodeBeginMessageField(facesContext, component);
@@ -61,9 +62,9 @@ public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    if (((SupportsLabelLayout) component).isNextToRenderIsLabel()) {
+    if (component.isNextToRenderIsLabel()) {
       // skip, because its only the lable to render
     } else {
       encodeEndMessageField(facesContext, component);
@@ -80,11 +81,11 @@ public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase
     encodeEndSurroundingLabel(facesContext, component);
   }
 
-  protected void encodeAttributes(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeAttributes(final FacesContext facesContext, final T component) throws IOException {
   }
 
   @Override
-  public void encodeChildren(final FacesContext context, final UIComponent component) throws IOException {
+  public void encodeChildrenInternal(final FacesContext context, final T component) throws IOException {
     if (component.getChildCount() > 0) {
       for (int i = 0, childCount = component.getChildCount(); i < childCount; i++) {
         final UIComponent child = component.getChildren().get(i);
@@ -101,19 +102,19 @@ public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase
     }
   }
 
-  protected abstract void encodeBeginMessageField(FacesContext facesContext, UIComponent component) throws IOException;
+  protected abstract void encodeBeginMessageField(FacesContext facesContext, T component) throws IOException;
 
-  protected abstract void encodeEndMessageField(FacesContext facesContext, UIComponent component) throws IOException;
+  protected abstract void encodeEndMessageField(FacesContext facesContext, T component) throws IOException;
 
-  protected void encodeBeginSurroundingLabel(final FacesContext facesContext, final UIComponent component)
+  protected void encodeBeginSurroundingLabel(final FacesContext facesContext, final T component)
       throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     String clientId = component.getClientId(facesContext);
     final Markup markup = (Markup) ComponentUtils.getAttribute(component, Attributes.markup);
 
-    final LabelLayout labelLayout = ((SupportsLabelLayout) component).getLabelLayout();
-    final boolean nextToRenderIsLabel = ((SupportsLabelLayout) component).isNextToRenderIsLabel();
+    final LabelLayout labelLayout = component.getLabelLayout();
+    final boolean nextToRenderIsLabel = component.isNextToRenderIsLabel();
     final boolean flex;
 
     switch (labelLayout) {
@@ -201,17 +202,17 @@ public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase
 //    }
   }
 
-  protected void encodeEndSurroundingLabel(final FacesContext facesContext, final UIComponent component)
+  protected void encodeEndSurroundingLabel(final FacesContext facesContext, final T component)
       throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final LabelLayout labelLayout = ((SupportsLabelLayout) component).getLabelLayout();
+    final LabelLayout labelLayout = component.getLabelLayout();
 
     if (labelLayout == LabelLayout.flexRight) {
       encodeLabel(facesContext, component, writer, labelLayout);
     }
 
-    final boolean nextToRenderIsLabel = ((SupportsLabelLayout) component).isNextToRenderIsLabel();
+    final boolean nextToRenderIsLabel = component.isNextToRenderIsLabel();
     if (!nextToRenderIsLabel) {
       writer.endElement(getComponentTag());
     }
@@ -221,7 +222,7 @@ public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase
     }
   }
 
-  protected void encodeLabel(final FacesContext facesContext, final UIComponent component,
+  protected void encodeLabel(final FacesContext facesContext, final T component,
                              final TobagoResponseWriter writer, final LabelLayout labelLayout)
       throws IOException {
     // TBD: maybe use an interface for getLabel()
@@ -240,5 +241,5 @@ public abstract class LabelLayoutRendererBase extends DecodingInputRendererBase
     }
   }
 
-  protected abstract String getFieldId(final FacesContext facesContext, final UIComponent component);
+  protected abstract String getFieldId(final FacesContext facesContext, final T component);
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelRenderer.java
index ea7b9fc..8a551f7 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelRenderer.java
@@ -43,7 +43,7 @@ import javax.faces.event.PostAddToViewEvent;
 import java.io.IOException;
 
 @ListenerFor(systemEventClass = PostAddToViewEvent.class)
-public class LabelRenderer extends RendererBase implements ComponentSystemEventListener {
+public class LabelRenderer<T extends AbstractUILabel> extends RendererBase<T> implements ComponentSystemEventListener {
 
   @Override
   public void processEvent(final ComponentSystemEvent event) {
@@ -51,19 +51,18 @@ public class LabelRenderer extends RendererBase implements ComponentSystemEventL
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUILabel label = (AbstractUILabel) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final UIComponent corresponding = ComponentUtils.findFor(label);
+    final UIComponent corresponding = ComponentUtils.findFor(component);
     final String forId;
     if (corresponding instanceof SupportFieldId) {
       forId = ((SupportFieldId) corresponding).getFieldId(facesContext);
     } else {
       forId = corresponding != null ? corresponding.getClientId(facesContext) : null;
     }
-    final String clientId = label.getClientId(facesContext);
-    final Markup markup = label.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final Markup markup = component.getMarkup();
     final boolean required;
     if (corresponding instanceof UIInput) {
       required = ((UIInput) corresponding).isRequired();
@@ -72,22 +71,22 @@ public class LabelRenderer extends RendererBase implements ComponentSystemEventL
     }
 
     writer.startElement(HtmlElements.LABEL);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, label);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeClassAttribute(
         BootstrapClass.COL_FORM_LABEL,
         TobagoClass.LABEL.createMarkup(markup),
         required ? TobagoClass.REQUIRED : null,
-        label.getCustomClass());
+        component.getCustomClass());
     writer.writeIdAttribute(clientId);
     if (forId != null) {
       writer.writeAttribute(HtmlAttributes.FOR, forId, false);
     }
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, label);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
 
-    encodeTextContent(facesContext, writer, label);
+    encodeTextContent(facesContext, writer, component);
 
     writer.endElement(HtmlElements.LABEL);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideCommandRenderer.java
index 12fafc5..fee9493 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideCommandRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideCommandRenderer.java
@@ -19,16 +19,16 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
+import org.apache.myfaces.tobago.internal.component.AbstractUILink;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
 import javax.faces.context.FacesContext;
 
-public class LinkInsideCommandRenderer extends LinkRenderer {
+public class LinkInsideCommandRenderer<T extends AbstractUILink> extends LinkRenderer<T> {
 
   @Override
-  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getOuterCssItems(final FacesContext facesContext, final T command) {
     return new CssItem[]{BootstrapClass.DROPDOWN_ITEM};
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideLinksRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideLinksRenderer.java
index c816c55..f33cc73 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideLinksRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkInsideLinksRenderer.java
@@ -19,7 +19,7 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
+import org.apache.myfaces.tobago.internal.component.AbstractUILink;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
@@ -28,10 +28,10 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class LinkInsideLinksRenderer extends LinkRenderer {
+public class LinkInsideLinksRenderer<T extends AbstractUILink> extends LinkRenderer<T> {
 
   @Override
-  protected void encodeBeginOuter(final FacesContext facesContext, final AbstractUICommand command) throws IOException {
+  protected void encodeBeginOuter(final FacesContext facesContext, final T command) throws IOException {
     final String clientId = command.getClientId(facesContext);
     final boolean parentOfCommands = command.isParentOfCommands();
 
@@ -49,7 +49,7 @@ public class LinkInsideLinksRenderer extends LinkRenderer {
   }
 
   @Override
-  protected void encodeEndOuter(final FacesContext facesContext, final AbstractUICommand command) throws IOException {
+  protected void encodeEndOuter(final FacesContext facesContext, final T command) throws IOException {
     final boolean parentOfCommands = command.isParentOfCommands();
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
@@ -61,7 +61,7 @@ public class LinkInsideLinksRenderer extends LinkRenderer {
   }
 
   @Override
-  protected CssItem[] getCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getCssItems(final FacesContext facesContext, final T command) {
     return new CssItem[]{BootstrapClass.NAV_LINK};
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkRenderer.java
index ab09aea..bc6a83d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinkRenderer.java
@@ -20,14 +20,14 @@
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
 import org.apache.myfaces.tobago.context.Markup;
-import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
+import org.apache.myfaces.tobago.internal.component.AbstractUILink;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 
 import javax.faces.context.FacesContext;
 
-public class LinkRenderer extends CommandRendererBase {
+public class LinkRenderer<T extends AbstractUILink> extends CommandRendererBase<T> {
 
   @Override
   protected TobagoClass getRendererCssClass() {
@@ -35,7 +35,7 @@ public class LinkRenderer extends CommandRendererBase {
   }
 
   @Override
-  protected CssItem[] getCssItems(final FacesContext facesContext, final AbstractUICommand command) {
+  protected CssItem[] getCssItems(final FacesContext facesContext, final T command) {
     final Markup markup = command.getMarkup() != null ? command.getMarkup() : Markup.NULL;
 
     return new CssItem[]{
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java
index 9baede8..86a28e9 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java
@@ -34,20 +34,19 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class LinksRenderer extends RendererBase {
+public class LinksRenderer<T extends AbstractUILinks> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUILinks links = (AbstractUILinks) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.startElement(HtmlElements.UL);
-    writer.writeIdAttribute(links.getClientId(facesContext));
+    writer.writeIdAttribute(component.getClientId(facesContext));
     writer.writeClassAttribute(
         TobagoClass.LINKS,
         getExtraCssItem(),
-        Orientation.vertical.equals(links.getOrientation()) ? BootstrapClass.FLEX_COLUMN : null,
-        links.getCustomClass());
+        Orientation.vertical.equals(component.getOrientation()) ? BootstrapClass.FLEX_COLUMN : null,
+        component.getCustomClass());
   }
 
   @Override
@@ -56,7 +55,7 @@ public class LinksRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     for (final UIComponent child : component.getChildren()) {
@@ -75,7 +74,7 @@ public class LinksRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.UL);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessageLayoutRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessageLayoutRendererBase.java
index 091ec26..29b6ee5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessageLayoutRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessageLayoutRendererBase.java
@@ -20,6 +20,7 @@
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
 import org.apache.myfaces.tobago.component.SupportsHelp;
+import org.apache.myfaces.tobago.component.SupportsLabelLayout;
 import org.apache.myfaces.tobago.internal.util.StringUtils;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
@@ -38,21 +39,22 @@ import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.util.List;
 
-public abstract class MessageLayoutRendererBase extends LabelLayoutRendererBase {
+public abstract class MessageLayoutRendererBase<T extends UIComponent & SupportsLabelLayout>
+    extends LabelLayoutRendererBase<T> {
 
   @Override
-  public void encodeBeginMessageField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginMessageField(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginMessagesContainer(facesContext, component);
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEndMessageField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndMessageField(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
     encodeEndMessagesContainer(facesContext, component);
   }
 
-  private void encodeBeginMessagesContainer(final FacesContext facesContext, final UIComponent component)
+  private void encodeBeginMessagesContainer(final FacesContext facesContext, final T component)
       throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
@@ -68,7 +70,7 @@ public abstract class MessageLayoutRendererBase extends LabelLayoutRendererBase
     }
   }
 
-  private void encodeEndMessagesContainer(final FacesContext facesContext, final UIComponent component)
+  private void encodeEndMessagesContainer(final FacesContext facesContext, final T component)
       throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
@@ -83,17 +85,19 @@ public abstract class MessageLayoutRendererBase extends LabelLayoutRendererBase
         encodeFacesMessagesButton(facesContext, component, writer, messages);
       }
       if (hasHelp) {
-        encodeHelpButton(facesContext, component, writer, help);
+        encodePopover(writer, component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "help",
+            BootstrapClass.BTN_OUTLINE_INFO, Icons.QUESTION,
+            ResourceUtils.getString(facesContext, "help.title"), help);
       }
       writer.endElement(HtmlElements.DIV);
     }
   }
 
-  protected abstract void encodeBeginField(FacesContext facesContext, UIComponent component) throws IOException;
+  protected abstract void encodeBeginField(FacesContext facesContext, T component) throws IOException;
 
-  protected abstract void encodeEndField(FacesContext facesContext, UIComponent component) throws IOException;
+  protected abstract void encodeEndField(FacesContext facesContext, T component) throws IOException;
 
-  private void encodeFacesMessagesButton(FacesContext facesContext, final UIComponent component,
+  private void encodeFacesMessagesButton(FacesContext facesContext, final T component,
       final TobagoResponseWriter writer, final List<FacesMessage> messages) throws IOException {
 
     encodePopover(writer, component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "messages",
@@ -187,14 +191,6 @@ public abstract class MessageLayoutRendererBase extends LabelLayoutRendererBase
     return stringBuilder.toString();
   }
 
-  private void encodeHelpButton(final FacesContext facesContext, final UIComponent component,
-      final TobagoResponseWriter writer, final String help) throws IOException {
-
-    encodePopover(writer, component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "help",
-        BootstrapClass.BTN_OUTLINE_INFO, Icons.QUESTION,
-        ResourceUtils.getString(facesContext, "help.title"), help);
-  }
-
   private void encodePopover(final TobagoResponseWriter writer, final String popoverId,
       final CssItem buttonColor, final Icons buttonIcon, final String title, final String content)
       throws IOException {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessagesRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessagesRenderer.java
index 6634576..d51dab0 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessagesRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MessagesRenderer.java
@@ -38,22 +38,19 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.faces.application.FacesMessage;
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.List;
 
-public class MessagesRenderer extends RendererBase {
+public class MessagesRenderer<T extends AbstractUIMessages> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIMessages messages = (AbstractUIMessages) component;
-
-    if (messages.isConfirmation()) {
+    if (component.isConfirmation()) {
       LOG.warn("'confirmation' is currently not supported for tc:messages!");
     }
 
@@ -62,7 +59,7 @@ public class MessagesRenderer extends RendererBase {
     if (LOG.isDebugEnabled()) {
       LOG.debug("facesContext is " + facesContext.getClass().getName());
     }
-    final List<AbstractUIMessages.Item> messageList = messages.createMessageList(facesContext);
+    final List<AbstractUIMessages.Item> messageList = component.createMessageList(facesContext);
 
     // with id
       /*String focusId = null;
@@ -76,12 +73,12 @@ public class MessagesRenderer extends RendererBase {
       }*/
 
     writer.startElement(HtmlElements.TOBAGO_MESSAGES);
-    writer.writeIdAttribute(messages.getClientId(facesContext));
-    final Markup markup = messages.getMarkup();
+    writer.writeIdAttribute(component.getClientId(facesContext));
+    final Markup markup = component.getMarkup();
     writer.writeClassAttribute(
         TobagoClass.MESSAGES,
         TobagoClass.MESSAGES.createMarkup(markup),
-        messages.getCustomClass());
+        component.getCustomClass());
 
     FacesMessage.Severity lastSeverity = null;
     boolean first = true;
@@ -98,7 +95,7 @@ public class MessagesRenderer extends RendererBase {
         writer.startElement(HtmlElements.DIV);
         writer.writeClassAttribute(
             BootstrapClass.ALERT, BootstrapClass.ALERT_DISMISSIBLE, BootstrapClass.alert(severity));
-        HtmlRendererUtils.writeDataAttributes(facesContext, writer, messages);
+        HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
         writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.ALERT.toString(), false);
 
         writer.startElement(HtmlElements.BUTTON);
@@ -109,7 +106,7 @@ public class MessagesRenderer extends RendererBase {
         writer.endElement(HtmlElements.BUTTON);
       }
 
-      encodeMessage(writer, messages, message, item.getClientId());
+      encodeMessage(writer, component, message, item.getClientId());
 
       lastSeverity = severity;
       first = false;
@@ -117,8 +114,8 @@ public class MessagesRenderer extends RendererBase {
     if (messageList.size() > 0) {
       writer.endElement(HtmlElements.DIV); // close open tag from for-loop
     }
-    if (messages.getFor() == null) {
-      final String id = messages.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "messagesExists";
+    if (component.getFor() == null) {
+      final String id = component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "messagesExists";
       writer.startElement(HtmlElements.INPUT);
       writer.writeAttribute(HtmlAttributes.VALUE, Boolean.TRUE.toString(), false);
       writer.writeAttribute(HtmlAttributes.ID, id, false);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaLinkRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaLinkRenderer.java
index c172481..92e8800 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaLinkRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaLinkRenderer.java
@@ -25,26 +25,24 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class MetaLinkRenderer extends RendererBase {
+public class MetaLinkRenderer<T extends AbstractUIMetaLink> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIMetaLink metaLink = (AbstractUIMetaLink) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.LINK);
-    writer.writeAttribute(HtmlAttributes.CHARSET, metaLink.getCharset(), true);
-    writer.writeAttribute(HtmlAttributes.HREF, metaLink.getHref(), true);
-    writer.writeAttribute(HtmlAttributes.HREFLANG, metaLink.getHreflang(), true);
-    writer.writeAttribute(HtmlAttributes.TYPE, metaLink.getType(), true);
-    writer.writeAttribute(HtmlAttributes.REL, metaLink.getRel(), true);
-    writer.writeAttribute(HtmlAttributes.REV, metaLink.getRev(), true);
-    writer.writeAttribute(HtmlAttributes.MEDIA, metaLink.getMedia(), true);
+    writer.writeAttribute(HtmlAttributes.CHARSET, component.getCharset(), true);
+    writer.writeAttribute(HtmlAttributes.HREF, component.getHref(), true);
+    writer.writeAttribute(HtmlAttributes.HREFLANG, component.getHreflang(), true);
+    writer.writeAttribute(HtmlAttributes.TYPE, component.getType(), true);
+    writer.writeAttribute(HtmlAttributes.REL, component.getRel(), true);
+    writer.writeAttribute(HtmlAttributes.REV, component.getRev(), true);
+    writer.writeAttribute(HtmlAttributes.MEDIA, component.getMedia(), true);
     writer.endElement(HtmlElements.LINK);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaRenderer.java
index b8939d2..e8cd6c0 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/MetaRenderer.java
@@ -25,24 +25,22 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class MetaRenderer extends RendererBase {
+public class MetaRenderer<T extends AbstractUIMeta> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIMeta meta = (AbstractUIMeta) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.META);
-    writer.writeAttribute(HtmlAttributes.NAME, meta.getName(), true);
-    writer.writeAttribute(HtmlAttributes.LANG, meta.getLang(), true);
-    writer.writeAttribute(HtmlAttributes.CHARSET, meta.getCharset(), true);
-    writer.writeAttribute(HtmlAttributes.HTTP_EQUIV, meta.getHttpEquiv(), true);
-    writer.writeAttribute(HtmlAttributes.CONTENT, meta.getContent(), true);
+    writer.writeAttribute(HtmlAttributes.NAME, component.getName(), true);
+    writer.writeAttribute(HtmlAttributes.LANG, component.getLang(), true);
+    writer.writeAttribute(HtmlAttributes.CHARSET, component.getCharset(), true);
+    writer.writeAttribute(HtmlAttributes.HTTP_EQUIV, component.getHttpEquiv(), true);
+    writer.writeAttribute(HtmlAttributes.CONTENT, component.getContent(), true);
     writer.endElement(HtmlElements.META);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ObjectRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ObjectRenderer.java
index 535f9e7..9ee88f1 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ObjectRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ObjectRenderer.java
@@ -29,43 +29,42 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ResourceUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class ObjectRenderer extends RendererBase {
+public class ObjectRenderer<T extends AbstractUIObject> extends RendererBase<T> {
+
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIObject object = (AbstractUIObject) component;
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Markup markup = object.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.IFRAME);
     writer.writeAttribute(HtmlAttributes.FRAMEBORDER, "0", false);
-    final String clientId = object.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     writer.writeIdAttribute(clientId);
-    String name = object.getName();
+    String name = component.getName();
     if (name == null) {
       name = clientId;
     }
     writer.writeNameAttribute(name);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, object);
-    writer.writeAttribute(HtmlAttributes.SRC, object.getSrc(), true);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+    writer.writeAttribute(HtmlAttributes.SRC, component.getSrc(), true);
     writer.writeClassAttribute(
         TobagoClass.OBJECT,
         TobagoClass.OBJECT.createMarkup(markup),
-        object.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
 
-    String sandbox = object.getSandbox();
+    String sandbox = component.getSandbox();
     if (sandbox != null) {
       writer.writeAttribute(HtmlAttributes.SANDBOX, sandbox, false);
     }
 
     writer.writeText(ResourceUtils.getString(facesContext, "object.noframe"));
     writer.writeText(" ");
-    if (object.getSrc() != null) {
-      writer.writeText(object.getSrc());
+    if (component.getSrc() != null) {
+      writer.writeText(component.getSrc());
     }
 
     writer.endElement(HtmlElements.IFRAME);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideBoxLabelRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideBoxLabelRenderer.java
index f24990c..90b6d6d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideBoxLabelRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideBoxLabelRenderer.java
@@ -22,19 +22,18 @@ package org.apache.myfaces.tobago.internal.renderkit.renderer;
 import org.apache.myfaces.tobago.internal.component.AbstractUIOut;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class OutInsideBoxLabelRenderer extends OutRenderer {
+public class OutInsideBoxLabelRenderer<T extends AbstractUIOut> extends OutRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideInRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideInRenderer.java
index 6d3be91..665a537 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideInRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideInRenderer.java
@@ -23,19 +23,18 @@ import org.apache.myfaces.tobago.internal.component.AbstractUIOut;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class OutInsideInRenderer extends OutRenderer {
+public class OutInsideInRenderer<T extends AbstractUIOut> extends OutRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideSectionLabelRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideSectionLabelRenderer.java
index 137e756..0320a0e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideSectionLabelRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutInsideSectionLabelRenderer.java
@@ -22,19 +22,18 @@ package org.apache.myfaces.tobago.internal.renderkit.renderer;
 import org.apache.myfaces.tobago.internal.component.AbstractUIOut;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class OutInsideSectionLabelRenderer extends OutRenderer {
+public class OutInsideSectionLabelRenderer<T extends AbstractUIOut> extends OutRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java
index 8e7f845..588339a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/OutRenderer.java
@@ -33,12 +33,11 @@ import org.apache.myfaces.tobago.sanitizer.SanitizeMode;
 import org.apache.myfaces.tobago.sanitizer.Sanitizer;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.util.StringTokenizer;
 
-public class OutRenderer extends MessageLayoutRendererBase {
+public class OutRenderer<T extends AbstractUIOut> extends MessageLayoutRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -46,49 +45,46 @@ public class OutRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIOut out = (AbstractUIOut) component;
-    final boolean plain = out.isPlain() || out.isCompact() || !out.isCreateSpan();
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
+    final boolean plain = component.isPlain() || component.isCompact() || !component.isCreateSpan();
 
     if (plain) {
-      encodeText(facesContext, out);
+      encodeText(facesContext, component);
     } else {
-      super.encodeBegin(facesContext, component);
+      super.encodeBeginInternal(facesContext, component);
     }
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIOut out = (AbstractUIOut) component;
-    final boolean plain = out.isPlain() || out.isCompact() || !out.isCreateSpan();
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
+    final boolean plain = component.isPlain() || component.isCompact() || !component.isCreateSpan();
 
     if (!plain) {
-      super.encodeEnd(facesContext, component);
+      super.encodeEndInternal(facesContext, component);
     }
   }
 
   @Override
-  public void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIOut out = (AbstractUIOut) component;
+  public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Markup markup = out.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.SPAN);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, out);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     writer.writeClassAttribute(
         TobagoClass.OUT,
         TobagoClass.OUT.createMarkup(markup),
-        getCssItems(facesContext, out),
+        getCssItems(facesContext, component),
         BootstrapClass.textColor(markup),
         BootstrapClass.fontStyle(markup),
-        out.getCustomClass());
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, out);
+        component.getCustomClass());
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
 
-    encodeText(facesContext, out);
+    encodeText(facesContext, component);
   }
 
   private void encodeText(final FacesContext facesContext, final AbstractUIOut out) throws IOException {
@@ -126,16 +122,13 @@ public class OutRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  public void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
-
-    final AbstractUIOut out = (AbstractUIOut) component;
+  public void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-
     writer.endElement(HtmlElements.SPAN);
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
+  protected String getFieldId(final FacesContext facesContext, final T component) {
     return component.getClientId(facesContext);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
index f570c41..d5ed108 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
@@ -77,7 +77,7 @@ import java.util.Map;
 
 // using jsf.js from a specific MyFaces version instead, to avoid old bugs
 //@ResourceDependency(name="jsf.js", library="javax.faces", target="head")
-public class PageRenderer extends RendererBase {
+public class PageRenderer<T extends AbstractUIPage> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -86,10 +86,9 @@ public class PageRenderer extends RendererBase {
   private static final String BODY_TARGET = "body";
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
 
-    final AbstractUIPage page = (AbstractUIPage) component;
-    final String clientId = page.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final ExternalContext externalContext = facesContext.getExternalContext();
 
     // last focus
@@ -104,14 +103,13 @@ public class PageRenderer extends RendererBase {
   private ProjectStage projectStage;
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIPage page = (AbstractUIPage) component;
     final TobagoConfig tobagoConfig = CDI.current().select(TobagoConfig.class).get(); // todo: may inject
     final TobagoContext tobagoContext = CDI.current().select(TobagoContext.class).get(); // todo: may inject
 
-    if (tobagoContext.getFocusId() == null && !StringUtils.isBlank(page.getFocusId())) {
-      tobagoContext.setFocusId(page.getFocusId());
+    if (tobagoContext.getFocusId() == null && !StringUtils.isBlank(component.getFocusId())) {
+      tobagoContext.setFocusId(component.getFocusId());
     }
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
@@ -127,7 +125,7 @@ public class PageRenderer extends RendererBase {
     ResponseUtils.ensureContentSecurityPolicyHeader(facesContext, tobagoConfig.getContentSecurityPolicy());
 
     if (LOG.isDebugEnabled()) {
-      for (final Object o : page.getAttributes().entrySet()) {
+      for (final Object o : component.getAttributes().entrySet()) {
         final Map.Entry entry = (Map.Entry) o;
         LOG.debug("*** '" + entry.getKey() + "' -> '" + entry.getValue() + "'");
       }
@@ -163,11 +161,11 @@ public class PageRenderer extends RendererBase {
       CookieUtils.setThemeNameToCookie((HttpServletRequest) request, (HttpServletResponse) response, theme.getName());
     }
 
-    final String clientId = page.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final boolean productionMode = projectStage == ProjectStage.Production;
-    final Markup markup = page.getMarkup();
+    final Markup markup = component.getMarkup();
     final TobagoClass spread = markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null;
-    final String title = page.getLabel();
+    final String title = component.getLabel();
 
     final Locale locale = viewRoot.getLocale();
     if (!portlet) {
@@ -244,13 +242,13 @@ public class PageRenderer extends RendererBase {
     writer.writeAttribute(CustomAttributes.LOCALE, locale.toString(), false);
     writer.writeClassAttribute(
         BootstrapClass.CONTAINER_FLUID,
-        TobagoClass.PAGE.createMarkup(portlet ? Markup.PORTLET.add(page.getMarkup()) : page.getMarkup()),
+        TobagoClass.PAGE.createMarkup(portlet ? Markup.PORTLET.add(component.getMarkup()) : component.getMarkup()),
         spread,
-        page.getCustomClass());
+        component.getCustomClass());
     writer.writeIdAttribute(clientId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, page);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
-    encodeBehavior(writer, facesContext, page);
+    encodeBehavior(writer, facesContext, component);
 
     writer.startElement(HtmlElements.FORM);
     writer.writeClassAttribute(spread);
@@ -261,8 +259,8 @@ public class PageRenderer extends RendererBase {
     if (LOG.isDebugEnabled()) {
       LOG.debug("partial action = " + partialAction);
     }
-    writer.writeIdAttribute(page.getFormId(facesContext));
-    writer.writeAttribute(HtmlAttributes.METHOD, getMethod(page), false);
+    writer.writeIdAttribute(component.getFormId(facesContext));
+    writer.writeAttribute(HtmlAttributes.METHOD, getMethod(component), false);
     final String enctype = tobagoContext.getEnctype();
     if (enctype != null) {
       writer.writeAttribute(HtmlAttributes.ENCTYPE, enctype, false);
@@ -324,12 +322,11 @@ public class PageRenderer extends RendererBase {
 */
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIPage page = (AbstractUIPage) component;
     final UIViewRoot viewRoot = facesContext.getViewRoot();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String clientId = page.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final Application application = facesContext.getApplication();
     final ViewHandler viewHandler = application.getViewHandler();
     final Object response = facesContext.getExternalContext().getResponse();
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java
index 71f3f7d..646c4da 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PanelRenderer.java
@@ -31,21 +31,19 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class PanelRenderer extends PanelRendererBase {
+public class PanelRenderer<T extends AbstractUIPanel> extends CollapsiblePanelRendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIPanel panel = (AbstractUIPanel) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String clientId = panel.getClientId(facesContext);
-    final boolean collapsed = panel.isCollapsed();
-    final Markup markup = panel.getMarkup();
-    final AbstractUIReload reload = ComponentUtils.getReloadFacet(panel);
+    final String clientId = component.getClientId(facesContext);
+    final boolean collapsed = component.isCollapsed();
+    final Markup markup = component.getMarkup();
+    final AbstractUIReload reload = ComponentUtils.getReloadFacet(component);
 
     writer.startElement(HtmlElements.TOBAGO_PANEL);
     writer.writeIdAttribute(clientId);
@@ -53,11 +51,11 @@ public class PanelRenderer extends PanelRendererBase {
     writer.writeClassAttribute(
         collapsed ? TobagoClass.COLLAPSED : null,
         TobagoClass.PANEL.createMarkup(markup),
-        panel.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
 
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, panel);
-    final String tip = panel.getTip();
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+    final String tip = component.getTip();
     if (tip != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, tip, true);
     }
@@ -66,15 +64,15 @@ public class PanelRenderer extends PanelRendererBase {
       writer.writeAttribute(DataAttributes.RELOAD, reload.getFrequency());
     }
 
-    if (panel.getCollapsedMode() != CollapseMode.none) {
+    if (component.getCollapsedMode() != CollapseMode.none) {
       encodeHidden(writer, clientId, collapsed);
     }
 
-    encodeBehavior(writer, facesContext, panel);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.TOBAGO_PANEL);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java
index 4072d86..42096f6 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PopupRenderer.java
@@ -30,33 +30,31 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlRoleValues;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class PopupRenderer extends PanelRendererBase {
+public class PopupRenderer<T extends AbstractUIPopup> extends CollapsiblePanelRendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIPopup popup = (AbstractUIPopup) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String clientId = popup.getClientId(facesContext);
-    final boolean collapsed = popup.isCollapsed();
-    final Markup markup = popup.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final boolean collapsed = component.isCollapsed();
+    final Markup markup = component.getMarkup();
 
     // this makes the popup NOT closable with a click to the background
-    ComponentUtils.putDataAttribute(popup, "backdrop", "static");
+    ComponentUtils.putDataAttribute(component, "backdrop", "static");
 
     writer.startElement(HtmlElements.TOBAGO_POPUP);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
         BootstrapClass.MODAL,
         BootstrapClass.FADE,
-        popup.getCustomClass());
+        component.getCustomClass());
     writer.writeAttribute(HtmlAttributes.TABINDEX, -1);
     writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.DIALOG.toString(), false);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, popup);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     // todo: aria-labelledby
     writer.startElement(HtmlElements.DIV);
     writer.writeClassAttribute(
@@ -67,13 +65,13 @@ public class PopupRenderer extends PanelRendererBase {
     writer.startElement(HtmlElements.DIV);
     writer.writeClassAttribute(BootstrapClass.MODAL_CONTENT);
 
-    if (popup.getCollapsedMode() != CollapseMode.none) {
+    if (component.getCollapsedMode() != CollapseMode.none) {
       encodeHidden(writer, clientId, collapsed);
     }
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ProgressRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ProgressRenderer.java
index cd53ee8..1cb6753 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ProgressRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ProgressRenderer.java
@@ -36,32 +36,29 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlRoleValues;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class ProgressRenderer extends RendererBase {
+public class ProgressRenderer<T extends AbstractUIProgress> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUIProgress progress = (AbstractUIProgress) component;
-
-    final double value = progress.getRangeValue();
-    final double max = progress.getRangeMax();
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
+    final double value = component.getRangeValue();
+    final double max = component.getRangeMax();
     final double percent = value / max;
-    final Markup markup = progress.getMarkup();
+    final Markup markup = component.getMarkup();
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.DIV);
-    final String clientId = progress.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
         TobagoClass.PROGRESS,
         TobagoClass.PROGRESS.createMarkup(markup),
         BootstrapClass.PROGRESS,
-        progress.getCustomClass());
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, progress);
+        component.getCustomClass());
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     writer.startElement(HtmlElements.DIV);
     writer.writeClassAttribute(BootstrapClass.PROGRESS_BAR);
@@ -75,13 +72,13 @@ public class ProgressRenderer extends RendererBase {
     style.setTransient(true);
     style.setSelector(StyleRenderUtils.encodeIdSelector(clientId) + ">." + BootstrapClass.PROGRESS_BAR.getName());
     style.setWidth(new Measure(percent * 100, Measure.Unit.PERCENT));
-    progress.getChildren().add(style);
+    component.getChildren().add(style);
 
-    encodeBehavior(writer, facesContext, progress);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RangeRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RangeRenderer.java
index e405bee..3a43596 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RangeRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RangeRenderer.java
@@ -30,17 +30,11 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
-import java.lang.invoke.MethodHandles;
 
-public class RangeRenderer extends MessageLayoutRendererBase {
-
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+public class RangeRenderer<T extends AbstractUIRange> extends MessageLayoutRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -48,32 +42,31 @@ public class RangeRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component)
+  protected void encodeBeginField(final FacesContext facesContext, final T component)
       throws IOException {
-    final AbstractUIRange range = (AbstractUIRange) component;
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, range);
-    final String currentValue = getCurrentValue(facesContext, range);
-    final String clientId = range.getClientId(facesContext);
-    final String fieldId = range.getFieldId(facesContext);
-    final boolean readonly = range.isReadonly();
-    final boolean disabled = range.isDisabled();
-    final int min = range.getMin();
-    final int max = range.getMax();
-    final int step = range.getStep();
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final String currentValue = getCurrentValue(facesContext, component);
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final boolean readonly = component.isReadonly();
+    final boolean disabled = component.isDisabled();
+    final int min = component.getMin();
+    final int max = component.getMax();
+    final int step = component.getStep();
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.INPUT);
 
-    if (range.getAccessKey() != null) {
-      writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(range.getAccessKey()), false);
-      AccessKeyLogger.addAccessKey(facesContext, range.getAccessKey(), clientId);
+    if (component.getAccessKey() != null) {
+      writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(component.getAccessKey()), false);
+      AccessKeyLogger.addAccessKey(facesContext, component.getAccessKey(), clientId);
     }
 
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.RANGE);
     writer.writeNameAttribute(clientId);
     writer.writeIdAttribute(fieldId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, range);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     if (currentValue != null) {
       writer.writeAttribute(HtmlAttributes.VALUE, currentValue, true);
     }
@@ -82,7 +75,7 @@ public class RangeRenderer extends MessageLayoutRendererBase {
     }
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, range.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
     writer.writeAttribute(HtmlAttributes.MIN, min);
     writer.writeAttribute(HtmlAttributes.MAX, max);
     writer.writeAttribute(HtmlAttributes.STEP, step);
@@ -90,17 +83,17 @@ public class RangeRenderer extends MessageLayoutRendererBase {
     final CssItem rendererCssClass = getRendererCssClass();
     writer.writeClassAttribute(
         rendererCssClass,
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(range)),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
         BootstrapClass.FORM_CONTROL,
-        range.getCustomClass());
+        component.getCustomClass());
 
-    HtmlRendererUtils.renderFocus(clientId, range.isFocus(), ComponentUtils.isError(range), facesContext, writer);
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
 
     writer.endElement(HtmlElements.INPUT);
 
     encodeTooltip(writer, currentValue);
 
-    encodeBehavior(writer, facesContext, range);
+    encodeBehavior(writer, facesContext, component);
   }
 
   private void encodeTooltip(final TobagoResponseWriter writer, final String content) throws IOException {
@@ -117,12 +110,10 @@ public class RangeRenderer extends MessageLayoutRendererBase {
     if (content != null) {
       writer.writeText(content);
     }
-    writer.endElement(HtmlElements.DIV);
-    writer.endElement(HtmlElements.DIV);
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
   }
 
   protected CssItem getRendererCssClass() {
@@ -130,8 +121,7 @@ public class RangeRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUIRange range = (AbstractUIRange) component;
-    return range.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RowRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RowRenderer.java
index 209e05a..a9379a9 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RowRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/RowRenderer.java
@@ -19,16 +19,17 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
+import org.apache.myfaces.tobago.internal.component.AbstractUICommandBase;
 import org.apache.myfaces.tobago.internal.component.AbstractUIEvent;
 
 import javax.faces.component.UIComponent;
 import javax.faces.event.ActionEvent;
 
-public class RowRenderer extends DecodingCommandRendererBase {
+public class RowRenderer<T extends AbstractUICommandBase> extends DecodingCommandRendererBase<T> {
 
   // XXX hack to fix TOBAGO-1572
   @Override
-  protected void commandActivated(final UIComponent component) {
+  protected void commandActivated(final T component) {
 
     AbstractUIEvent event = null;
     for (final UIComponent uiComponent : component.getChildren()) {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ScriptRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ScriptRenderer.java
index dcc0082..6860b34 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ScriptRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/ScriptRenderer.java
@@ -25,21 +25,19 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class ScriptRenderer extends RendererBase {
+public class ScriptRenderer<T extends AbstractUIScript> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIScript script = (AbstractUIScript) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.SCRIPT);
-    writer.writeAttribute(HtmlAttributes.SRC, script.getFile(), true);
-    writer.writeAttribute(HtmlAttributes.TYPE, script.getType(), true);
+    writer.writeAttribute(HtmlAttributes.SRC, component.getFile(), true);
+    writer.writeAttribute(HtmlAttributes.TYPE, component.getType(), true);
     writer.endElement(HtmlElements.SCRIPT);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SectionRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SectionRenderer.java
index 6adf3be..5c16808 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SectionRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SectionRenderer.java
@@ -36,16 +36,15 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SectionRenderer extends PanelRendererBase {
+public class SectionRenderer<T extends AbstractUISection> extends CollapsiblePanelRendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISection section = (AbstractUISection) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String clientId = section.getClientId(facesContext);
-    final boolean collapsed = section.isCollapsed();
-    final Markup markup = section.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final boolean collapsed = component.isCollapsed();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.DIV);
     writer.writeIdAttribute(clientId);
@@ -53,11 +52,11 @@ public class SectionRenderer extends PanelRendererBase {
         TobagoClass.SECTION,
         TobagoClass.SECTION.createMarkup(markup),
         collapsed ? TobagoClass.COLLAPSED : null,
-        section.getCustomClass());
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, section);
+        component.getCustomClass());
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     final HtmlElements tag;
-    switch (section.getLevel()) {
+    switch (component.getLevel()) {
       case 1:
         tag = HtmlElements.H1;
         break;
@@ -77,7 +76,7 @@ public class SectionRenderer extends PanelRendererBase {
         tag = HtmlElements.H6;
     }
 
-    if (section.getCollapsedMode() != CollapseMode.none) {
+    if (component.getCollapsedMode() != CollapseMode.none) {
       encodeHidden(writer, clientId, collapsed);
     }
 
@@ -85,11 +84,11 @@ public class SectionRenderer extends PanelRendererBase {
     writer.writeClassAttribute(TobagoClass.SECTION__HEADER);
     writer.startElement(tag);
 
-    final String image = section.getImage();
+    final String image = component.getImage();
     HtmlRendererUtils.encodeIconOrImage(writer, image);
 
-    final UIComponent labelFacet = ComponentUtils.getFacet(section, Facets.label);
-    final String labelString = section.getLabel();
+    final UIComponent labelFacet = ComponentUtils.getFacet(component, Facets.label);
+    final String labelString = component.getLabel();
     if (labelFacet != null) {
       for (final UIComponent child : RenderUtils.getFacetChildren(labelFacet)) {
         if (child instanceof AbstractUIOut) {
@@ -104,7 +103,7 @@ public class SectionRenderer extends PanelRendererBase {
     }
     writer.endElement(tag);
 
-    final UIComponent bar = ComponentUtils.getFacet(section, Facets.bar);
+    final UIComponent bar = ComponentUtils.getFacet(component, Facets.bar);
     if (bar != null) {
       bar.encodeAll(facesContext);
     }
@@ -116,7 +115,7 @@ public class SectionRenderer extends PanelRendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SegmentLayoutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SegmentLayoutRenderer.java
index ad6a361..0dacee7 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SegmentLayoutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SegmentLayoutRenderer.java
@@ -40,7 +40,7 @@ import java.util.List;
 /**
  * Renders the 12 columns grid layout.
  */
-public class SegmentLayoutRenderer extends RendererBase {
+public class SegmentLayoutRenderer<T extends AbstractUISegmentLayout> extends RendererBase<T> {
 
   @Override
   public boolean getRendersChildren() {
@@ -48,15 +48,14 @@ public class SegmentLayoutRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISegmentLayout layout = (AbstractUISegmentLayout) component;
-    final Markup markup = layout.getMarkup();
-    final SegmentJustify segmentJustify = layout.getJustify();
+    final Markup markup = component.getMarkup();
+    final SegmentJustify segmentJustify = component.getJustify();
 
     writer.startElement(HtmlElements.DIV);
-    writer.writeIdAttribute(layout.getClientId(facesContext));
+    writer.writeIdAttribute(component.getClientId(facesContext));
 //    writer.writeClassAttribute(BootstrapClass.FORM_HORIZONTAL, BootstrapClass.CONTAINER_FLUID);
     writer.writeClassAttribute(
         TobagoClass.SEGMENT_LAYOUT,
@@ -68,27 +67,25 @@ public class SegmentLayoutRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISegmentLayout segmentLayout = (AbstractUISegmentLayout) component;
 
-    if (!segmentLayout.isRendered()) {
+    if (!component.isRendered()) {
       return;
     }
 
-//    final List<UIComponent> children = segmentLayout.getChildren();
-    final List<UIComponent> children = ComponentUtils.findLayoutChildren(segmentLayout);
+    final List<UIComponent> children = ComponentUtils.findLayoutChildren(component);
     final BootstrapClass.Generator generator = new BootstrapClass.Generator(
-        segmentLayout.getExtraSmall(),
-        segmentLayout.getSmall(),
-        segmentLayout.getMedium(),
-        segmentLayout.getLarge(),
-        segmentLayout.getExtraLarge(),
-        MarginTokens.parse(segmentLayout.getMarginExtraSmall()),
-        MarginTokens.parse(segmentLayout.getMarginSmall()),
-        MarginTokens.parse(segmentLayout.getMarginMedium()),
-        MarginTokens.parse(segmentLayout.getMarginLarge()),
-        MarginTokens.parse(segmentLayout.getMarginExtraLarge()));
+        component.getExtraSmall(),
+        component.getSmall(),
+        component.getMedium(),
+        component.getLarge(),
+        component.getExtraLarge(),
+        MarginTokens.parse(component.getMarginExtraSmall()),
+        MarginTokens.parse(component.getMarginSmall()),
+        MarginTokens.parse(component.getMarginMedium()),
+        MarginTokens.parse(component.getMarginLarge()),
+        MarginTokens.parse(component.getMarginExtraLarge()));
     for (final UIComponent child : children) {
       if (child.isRendered()) {
         encodeChild(facesContext, writer, generator, child);
@@ -133,7 +130,7 @@ public class SegmentLayoutRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxInsideCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxInsideCommandRenderer.java
index 068df56..657a39c 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxInsideCommandRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxInsideCommandRenderer.java
@@ -20,23 +20,24 @@
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
 import org.apache.myfaces.tobago.internal.component.AbstractUISelectBoolean;
+import org.apache.myfaces.tobago.internal.component.AbstractUISelectBooleanCheckbox;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SelectBooleanCheckboxInsideCommandRenderer extends SelectBooleanCheckboxRenderer {
+public class SelectBooleanCheckboxInsideCommandRenderer<T extends AbstractUISelectBooleanCheckbox>
+    extends SelectBooleanCheckboxRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxRenderer.java
index c0ad340..8a554d5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectBooleanCheckboxRenderer.java
@@ -21,6 +21,7 @@ package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
 import org.apache.myfaces.tobago.context.Markup;
 import org.apache.myfaces.tobago.internal.component.AbstractUISelectBoolean;
+import org.apache.myfaces.tobago.internal.component.AbstractUISelectBooleanCheckbox;
 import org.apache.myfaces.tobago.internal.util.AccessKeyLogger;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
@@ -35,35 +36,32 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIInput;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 
-public class SelectBooleanCheckboxRenderer extends MessageLayoutRendererBase {
+public class SelectBooleanCheckboxRenderer<T extends AbstractUISelectBooleanCheckbox>
+    extends MessageLayoutRendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
 
-    final UIInput input = (UIInput) component;
-
-    if (ComponentUtils.isOutputOnly(input)) {
+    if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
     final String newValue = facesContext.getExternalContext()
-        .getRequestParameterMap().get(input.getClientId(facesContext));
+        .getRequestParameterMap().get(component.getClientId(facesContext));
 
     if (LOG.isDebugEnabled()) {
       LOG.debug("new value = '" + newValue + "'");
     }
 
-    input.setSubmittedValue("true".equals(newValue) ? "true" : "false");
+    component.setSubmittedValue("true".equals(newValue) ? "true" : "false");
 
-    decodeClientBehaviors(facesContext, input);
+    decodeClientBehaviors(facesContext, component);
   }
 
   @Override
@@ -72,30 +70,29 @@ public class SelectBooleanCheckboxRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISelectBoolean select = (AbstractUISelectBoolean) component;
+  protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String clientId = select.getClientId(facesContext);
-    final String fieldId = select.getFieldId(facesContext);
-    final String currentValue = getCurrentValue(facesContext, select);
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final String currentValue = getCurrentValue(facesContext, component);
     final boolean checked = "true".equals(currentValue);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
-    final boolean disabled = select.isDisabled();
-    final LabelWithAccessKey label = new LabelWithAccessKey(select, true);
-    final String itemLabel = select.getItemLabel();
-    final String itemImage = select.getItemImage();
-    final Markup markup = select.getMarkup();
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final boolean disabled = component.isDisabled();
+    final LabelWithAccessKey label = new LabelWithAccessKey(component, true);
+    final String itemLabel = component.getItemLabel();
+    final String itemImage = component.getItemImage();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(getOuterHtmlTag());
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
         getTobagoClass(),
         getTobagoClass().createMarkup(markup),
-        getOuterCssItems(facesContext, select),
-        select.getCustomClass());
+        getOuterCssItems(facesContext, component),
+        component.getCustomClass());
 
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
@@ -107,17 +104,17 @@ public class SelectBooleanCheckboxRenderer extends MessageLayoutRendererBase {
     writer.writeNameAttribute(clientId);
     writer.writeIdAttribute(fieldId);
     writer.writeAttribute(HtmlAttributes.CHECKED, checked);
-    writer.writeAttribute(HtmlAttributes.READONLY, select.isReadonly());
+    writer.writeAttribute(HtmlAttributes.READONLY, component.isReadonly());
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
-    writer.writeAttribute(HtmlAttributes.REQUIRED, select.isRequired());
-    HtmlRendererUtils.renderFocus(clientId, select.isFocus(), ComponentUtils.isError(select), facesContext, writer);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
     writer.endElement(HtmlElements.INPUT);
 
     writer.startElement(HtmlElements.LABEL);
     writer.writeClassAttribute(
         BootstrapClass.FORM_CHECK_LABEL,
-        getCssItems(facesContext, select));
+        getCssItems(facesContext, component));
     if (!disabled && label.getAccessKey() != null) {
       writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(label.getAccessKey()), false);
       AccessKeyLogger.addAccessKey(facesContext, label.getAccessKey(), clientId);
@@ -129,8 +126,8 @@ public class SelectBooleanCheckboxRenderer extends MessageLayoutRendererBase {
       writer.writeAttribute(HtmlAttributes.ALT, "", false);
       writer.endElement(HtmlElements.IMG);
     }
-    if (itemLabel != null && select.getLabel() == null && select.getAccessKey() != null) {
-      if (itemLabel.contains(Character.toString(select.getAccessKey()))) {
+    if (itemLabel != null && component.getLabel() == null && component.getAccessKey() != null) {
+      if (itemLabel.contains(Character.toString(component.getAccessKey()))) {
         HtmlRendererUtils.writeLabelWithAccessKey(writer, label);
       }
     } else if (itemLabel != null) {
@@ -144,13 +141,12 @@ public class SelectBooleanCheckboxRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectBoolean select = (AbstractUISelectBoolean) component;
 
     writer.endElement(getOuterHtmlTag());
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   protected HtmlElements getOuterHtmlTag() {
@@ -169,8 +165,7 @@ public class SelectBooleanCheckboxRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUISelectBoolean select = (AbstractUISelectBoolean) component;
-    return select.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxInsideCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxInsideCommandRenderer.java
index 631c080..09150af 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxInsideCommandRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxInsideCommandRenderer.java
@@ -24,19 +24,19 @@ import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SelectManyCheckboxInsideCommandRenderer extends SelectManyCheckboxRenderer {
+public class SelectManyCheckboxInsideCommandRenderer<T extends AbstractUISelectManyCheckbox>
+    extends SelectManyCheckboxRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java
index 46b7956..55546e8 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyCheckboxRenderer.java
@@ -35,12 +35,11 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 import java.io.IOException;
 
-public class SelectManyCheckboxRenderer extends SelectManyRendererBase {
+public class SelectManyCheckboxRenderer<T extends AbstractUISelectManyCheckbox> extends SelectManyRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -48,36 +47,35 @@ public class SelectManyCheckboxRenderer extends SelectManyRendererBase {
   }
 
   @Override
-  public void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISelectManyCheckbox select = (AbstractUISelectManyCheckbox) component;
-    final AbstractUISelectReference reference = select.getRenderRangeReference();
+  public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
+    final AbstractUISelectReference reference = component.getRenderRangeReference();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String id = select.getClientId(facesContext);
-    final String referenceId = reference != null ? reference.getClientId(facesContext) : id;
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
-    final boolean disabled = select.isDisabled();
-    final boolean readonly = select.isReadonly();
-    final boolean required = select.isRequired();
-    final boolean inline = select.isInline();
-    final Markup markup = select.getMarkup();
+    final String id = component.getClientId(facesContext);
+//    final String referenceId = reference != null ? reference.getClientId(facesContext) : id;
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final boolean disabled = component.isDisabled();
+    final boolean readonly = component.isReadonly();
+    final boolean required = component.isRequired();
+    final boolean inline = component.isInline();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(getOuterHtmlTag());
     writer.writeClassAttribute(
         TobagoClass.SELECT_MANY_CHECKBOX,
         TobagoClass.SELECT_MANY_CHECKBOX.createMarkup(markup),
         inline ? TobagoClass.SELECT_MANY_CHECKBOX__INLINE : null,
-        select.getCustomClass());
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
+        component.getCustomClass());
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
     boolean first = true;
-    final Object[] values = select.getSelectedValues();
-    final String[] submittedValues = getSubmittedValues(select);
+    final Object[] values = component.getSelectedValues();
+    final String[] submittedValues = getSubmittedValues(component);
     int i = 0;
-    final int[] renderRange = getRenderRangeList(select, reference);
-    for (final SelectItem item : SelectItemUtils.getItemIterator(facesContext, select)) {
+    final int[] renderRange = getRenderRangeList(component, reference);
+    for (final SelectItem item : SelectItemUtils.getItemIterator(facesContext, component)) {
       if (renderRange == null || ArrayUtils.contains(renderRange, i)) {
         final boolean itemDisabled = item.isDisabled() || disabled;
         final String itemId = id + ComponentUtils.SUB_SEPARATOR + i;
@@ -88,7 +86,7 @@ public class SelectManyCheckboxRenderer extends SelectManyRendererBase {
         writer.startElement(HtmlElements.INPUT);
         writer.writeClassAttribute(BootstrapClass.FORM_CHECK_INPUT);
         writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.CHECKBOX);
-        final String formattedValue = ComponentUtils.getFormattedValue(facesContext, select, item.getValue());
+        final String formattedValue = ComponentUtils.getFormattedValue(facesContext, component, item.getValue());
         final boolean checked;
         if (submittedValues == null) {
           checked = ArrayUtils.contains(values, item.getValue());
@@ -103,16 +101,16 @@ public class SelectManyCheckboxRenderer extends SelectManyRendererBase {
         writer.writeAttribute(HtmlAttributes.READONLY, readonly);
         writer.writeAttribute(HtmlAttributes.REQUIRED, required);
         if (first) {
-          HtmlRendererUtils.renderFocus(id, select.isFocus(), ComponentUtils.isError(select), facesContext, writer);
+          HtmlRendererUtils.renderFocus(id, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
           first = false;
         }
-        writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+        writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
         writer.endElement(HtmlElements.INPUT);
 
         writer.startElement(HtmlElements.LABEL);
         writer.writeClassAttribute(
             BootstrapClass.FORM_CHECK_LABEL,
-            getCssItems(facesContext, select));
+            getCssItems(facesContext, component));
         writer.writeAttribute(HtmlAttributes.FOR, itemId, false);
 
         if (item instanceof org.apache.myfaces.tobago.model.SelectItem) {
@@ -146,13 +144,12 @@ public class SelectManyCheckboxRenderer extends SelectManyRendererBase {
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectManyCheckbox select = (AbstractUISelectManyCheckbox) component;
 
     writer.endElement(getOuterHtmlTag());
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   protected HtmlElements getOuterHtmlTag() {
@@ -164,7 +161,7 @@ public class SelectManyCheckboxRenderer extends SelectManyRendererBase {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
+  protected String getFieldId(final FacesContext facesContext, final T component) {
     return component.getClientId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java
index 5bc4c6d..149d6ab 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java
@@ -30,13 +30,12 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 import java.io.IOException;
 import java.util.List;
 
-public class SelectManyListboxRenderer extends SelectManyRendererBase {
+public class SelectManyListboxRenderer<T extends AbstractUISelectManyListbox> extends SelectManyRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -49,60 +48,57 @@ public class SelectManyListboxRenderer extends SelectManyRendererBase {
   }
 
   @Override
-  public void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISelectManyListbox select = (AbstractUISelectManyListbox) component;
+  public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String clientId = select.getClientId(facesContext);
-    final String fieldId = select.getFieldId(facesContext);
-    final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, select);
-    final boolean readonly = select.isReadonly();
-    final boolean disabled = !items.iterator().hasNext() || select.isDisabled() || readonly;
-    final Markup markup = select.getMarkup();
-    Integer size = select.getSize();
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
+    final boolean readonly = component.isReadonly();
+    final boolean disabled = !items.iterator().hasNext() || component.isDisabled() || readonly;
+    final Markup markup = component.getMarkup();
+    Integer size = component.getSize();
     size = Math.max(size != null ? size : items.size(), 2); // must be > 1
 
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     writer.startElement(HtmlElements.SELECT);
     writer.writeIdAttribute(fieldId);
     writer.writeNameAttribute(clientId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
-    writer.writeAttribute(HtmlAttributes.REQUIRED, select.isRequired());
-    HtmlRendererUtils.renderFocus(clientId, select.isFocus(), ComponentUtils.isError(select), facesContext, writer);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
 
     writer.writeClassAttribute(
         TobagoClass.SELECT_MANY_LISTBOX,
-        TobagoClass.SELECT_MANY_LISTBOX.createMarkup(select.getMarkup()),
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(select)),
+        TobagoClass.SELECT_MANY_LISTBOX.createMarkup(component.getMarkup()),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
         BootstrapClass.FORM_CONTROL,
-        select.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
     writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
     writer.writeAttribute(HtmlAttributes.SIZE, size);
     writer.writeAttribute(HtmlAttributes.TITLE, title, true);
-    final Object[] values = select.getSelectedValues();
-    final String[] submittedValues = getSubmittedValues(select);
+    final Object[] values = component.getSelectedValues();
+    final String[] submittedValues = getSubmittedValues(component);
 
-    HtmlRendererUtils.renderSelectItems(select, TobagoClass.SELECT_MANY_LISTBOX__OPTION, items, values, submittedValues,
+    HtmlRendererUtils.renderSelectItems(component, TobagoClass.SELECT_MANY_LISTBOX__OPTION, items, values, submittedValues,
         writer, facesContext);
   }
 
   @Override
-  public void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectManyListbox select = (AbstractUISelectManyListbox) component;
 
     writer.endElement(HtmlElements.SELECT);
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUISelectManyListbox select = (AbstractUISelectManyListbox) component;
-    return select.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java
index 6286208..896b79e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java
@@ -55,20 +55,18 @@ import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
-public abstract class SelectManyRendererBase extends MessageLayoutRendererBase {
+public abstract class SelectManyRendererBase<T extends AbstractUISelectManyBase> extends MessageLayoutRendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
-    final AbstractUISelectManyBase select = (AbstractUISelectManyBase) component;
-
     String[] newValues =
-        facesContext.getExternalContext().getRequestParameterValuesMap().get(select.getClientId(facesContext));
+        facesContext.getExternalContext().getRequestParameterValuesMap().get(component.getClientId(facesContext));
     if (LOG.isDebugEnabled()) {
       LOG.debug("decode: key='" + component.getClientId(facesContext)
           + "' value='" + Arrays.toString(newValues) + "'");
@@ -83,9 +81,9 @@ public abstract class SelectManyRendererBase extends MessageLayoutRendererBase {
     if (newValues == null) {
       newValues = ArrayUtils.EMPTY_STRING_ARRAY; // because no selection will not submitted by browsers
     }
-    select.setSubmittedValue(newValues);
+    component.setSubmittedValue(newValues);
 
-    decodeClientBehaviors(facesContext, select);
+    decodeClientBehaviors(facesContext, component);
   }
 
   public String[] getSubmittedValues(final UIInput input) {
@@ -93,8 +91,8 @@ public abstract class SelectManyRendererBase extends MessageLayoutRendererBase {
   }
 
   @Override
-  public Object getConvertedValue(
-      final FacesContext facesContext, final UIComponent component, final Object submittedValue)
+  public Object getConvertedValueInternal(
+      final FacesContext facesContext, final T component, final Object submittedValue)
       throws ConverterException {
 
     if (submittedValue == null) {
@@ -105,7 +103,7 @@ public abstract class SelectManyRendererBase extends MessageLayoutRendererBase {
             + component.getClientId(facesContext) + "expected");
       }
     }
-    return getConvertedUISelectManyValue(facesContext, (UISelectMany) component, (String[]) submittedValue);
+    return getConvertedUISelectManyValue(facesContext, component, (String[]) submittedValue);
   }
 
   // #################################################################################################################
@@ -236,8 +234,7 @@ public abstract class SelectManyRendererBase extends MessageLayoutRendererBase {
           }
         } else if (Collection.class.isAssignableFrom(modelType)) {
           // component.getValue() will implement Collection at this point
-          final Collection<?> componentValue = (Collection<?>) component
-              .getValue();
+          final Collection<?> componentValue = (Collection<?>) component.getValue();
           // can we clone the Collection
           if (componentValue instanceof Cloneable) {
             // clone method of Object is protected --> use reflection
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyShuttleRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyShuttleRenderer.java
index b43d9fc..4c01a67 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyShuttleRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyShuttleRenderer.java
@@ -38,7 +38,7 @@ import javax.faces.model.SelectItem;
 import java.io.IOException;
 import java.util.List;
 
-public class SelectManyShuttleRenderer extends SelectManyRendererBase {
+public class SelectManyShuttleRenderer<T extends AbstractUISelectManyShuttle> extends SelectManyRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -46,37 +46,36 @@ public class SelectManyShuttleRenderer extends SelectManyRendererBase {
   }
 
   @Override
-  public void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectManyShuttle select = (AbstractUISelectManyShuttle) component;
-    final String clientId = select.getClientId(facesContext);
-    final Markup markup = select.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.DIV);
     writer.writeClassAttribute(
         TobagoClass.SELECT_MANY_SHUTTLE,
         TobagoClass.SELECT_MANY_SHUTTLE.createMarkup(markup),
-        select.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
-    final boolean hasLabel = select.hasLabel();
-    final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, select);
-    final boolean disabled = !items.iterator().hasNext() || select.isDisabled();
-    final boolean readonly = select.isReadonly();
+//    final boolean hasLabel = component.hasLabel(); // XXX is needed?
+    final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
+    final boolean disabled = !items.iterator().hasNext() || component.isDisabled();
+    final boolean readonly = component.isReadonly();
 
-    final String unselectedLabel = select.getUnselectedLabel();
+    final String unselectedLabel = component.getUnselectedLabel();
     if (unselectedLabel != null) {
       writer.startElement(HtmlElements.DIV);
       writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__UNSELECTED_LABEL);
       writer.write(unselectedLabel);
       writer.endElement(HtmlElements.DIV);
     }
-    Integer size = select.getSize();
+    Integer size = component.getSize();
     size = Math.max(size != null ? size : items.size(), 2); // must be > 1
 
     writer.startElement(HtmlElements.SELECT);
@@ -86,16 +85,16 @@ public class SelectManyShuttleRenderer extends SelectManyRendererBase {
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
 
     // TODO tabIndex
-    writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
 
     writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__UNSELECTED, BootstrapClass.FORM_CONTROL);
 
     writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
     writer.writeAttribute(HtmlAttributes.SIZE, size);
 
-    final Object[] values = select.getSelectedValues();
-    final String[] submittedValues = getSubmittedValues(select);
-    HtmlRendererUtils.renderSelectItems(select, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues,
+    final Object[] values = component.getSelectedValues();
+    final String[] submittedValues = getSubmittedValues(component);
+    HtmlRendererUtils.renderSelectItems(component, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues,
         false, writer, facesContext);
 
     writer.endElement(HtmlElements.SELECT);
@@ -110,7 +109,7 @@ public class SelectManyShuttleRenderer extends SelectManyRendererBase {
     createButton(facesContext, component, writer, disabled | readonly,
         Icons.ANGLE_DOUBLE_LEFT, "removeAll", TobagoClass.SELECT_MANY_SHUTTLE__REMOVE_ALL);
     writer.endElement(HtmlElements.DIV);
-    final String selectedLabel = select.getSelectedLabel();
+    final String selectedLabel = component.getSelectedLabel();
     if (selectedLabel != null) {
       writer.startElement(HtmlElements.DIV);
       writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__SELECTED_LABEL);
@@ -124,14 +123,14 @@ public class SelectManyShuttleRenderer extends SelectManyRendererBase {
 
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
     writer.writeClassAttribute(
         TobagoClass.SELECT_MANY_SHUTTLE__SELECTED,
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(select)),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
         BootstrapClass.FORM_CONTROL);
     writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
     writer.writeAttribute(HtmlAttributes.SIZE, size);
-    HtmlRendererUtils.renderSelectItems(select, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues,
+    HtmlRendererUtils.renderSelectItems(component, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues,
         true, writer, facesContext);
 
     writer.endElement(HtmlElements.SELECT);
@@ -141,19 +140,18 @@ public class SelectManyShuttleRenderer extends SelectManyRendererBase {
     writer.writeIdAttribute(hiddenClientId);
     writer.writeNameAttribute(clientId);
     writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
-    writer.writeAttribute(HtmlAttributes.REQUIRED, select.isRequired());
-    HtmlRendererUtils.renderSelectItems(select, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues,
+    writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
+    HtmlRendererUtils.renderSelectItems(component, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues,
         writer, facesContext);
     writer.endElement(HtmlElements.SELECT);
   }
 
   @Override
-  public void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectManyShuttle select = (AbstractUISelectManyShuttle) component;
     writer.endElement(HtmlElements.DIV);
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   private void createButton(
@@ -171,7 +169,7 @@ public class SelectManyShuttleRenderer extends SelectManyRendererBase {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
+  protected String getFieldId(final FacesContext facesContext, final T component) {
     return component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "unselected";
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceInsideInRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceInsideInRenderer.java
index b9dc351..c482410 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceInsideInRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceInsideInRenderer.java
@@ -23,19 +23,18 @@ import org.apache.myfaces.tobago.internal.component.AbstractUISelectOneChoice;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SelectOneChoiceInsideInRenderer extends SelectOneChoiceRenderer {
+public class SelectOneChoiceInsideInRenderer<T extends AbstractUISelectOneChoice> extends SelectOneChoiceRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
@@ -45,7 +44,7 @@ public class SelectOneChoiceInsideInRenderer extends SelectOneChoiceRenderer {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
+  protected String getFieldId(final FacesContext facesContext, final T component) {
     return component.getClientId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
index 4e3c7a0..6c2e888 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
@@ -31,12 +31,11 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 import java.io.IOException;
 
-public class SelectOneChoiceRenderer extends SelectOneRendererBase {
+public class SelectOneChoiceRenderer<T extends AbstractUISelectOneChoice> extends SelectOneRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -49,53 +48,50 @@ public class SelectOneChoiceRenderer extends SelectOneRendererBase {
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISelectOneChoice select = (AbstractUISelectOneChoice) component;
+  protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String clientId = select.getClientId(facesContext);
-    final String fieldId = getFieldId(facesContext, select);
-    final Iterable<SelectItem> items = SelectItemUtils.getItemIterator(facesContext, select);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
-    final boolean disabled = !items.iterator().hasNext() || select.isDisabled() || select.isReadonly();
-    final Markup markup = select.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = getFieldId(facesContext, component);
+    final Iterable<SelectItem> items = SelectItemUtils.getItemIterator(facesContext, component);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final boolean disabled = !items.iterator().hasNext() || component.isDisabled() || component.isReadonly();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.SELECT);
     writer.writeIdAttribute(fieldId);
     writer.writeNameAttribute(clientId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
 
     writer.writeClassAttribute(
         TobagoClass.SELECT_ONE_CHOICE,
         TobagoClass.SELECT_ONE_CHOICE.createMarkup(markup),
-        getCssItems(facesContext, select),
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(select)),
-        select.getCustomClass());
+        getCssItems(facesContext, component),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
+        component.getCustomClass());
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
-    HtmlRendererUtils.renderFocus(clientId, select.isFocus(), ComponentUtils.isError(select), facesContext, writer);
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
 
-    HtmlRendererUtils.renderSelectItems(select, TobagoClass.SELECT_ONE_CHOICE__OPTION, items, select.getValue(),
-        (String) select.getSubmittedValue(), writer, facesContext);
+    HtmlRendererUtils.renderSelectItems(component, TobagoClass.SELECT_ONE_CHOICE__OPTION, items, component.getValue(),
+        (String) component.getSubmittedValue(), writer, facesContext);
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectOneChoice select = (AbstractUISelectOneChoice) component;
 
     writer.endElement(HtmlElements.SELECT);
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUISelectOneChoice select = (AbstractUISelectOneChoice) component;
-    return select.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 
   protected CssItem[] getCssItems(final FacesContext facesContext, final AbstractUISelectOneChoice select) {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListboxRenderer.java
index 4c6564f..db28aa4 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneListboxRenderer.java
@@ -30,13 +30,12 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 import java.io.IOException;
 import java.util.List;
 
-public class SelectOneListboxRenderer extends SelectOneRendererBase {
+public class SelectOneListboxRenderer<T extends AbstractUISelectOneListbox> extends SelectOneRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -49,56 +48,53 @@ public class SelectOneListboxRenderer extends SelectOneRendererBase {
   }
 
   @Override
-  public void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISelectOneListbox select = (AbstractUISelectOneListbox) component;
+  public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String clientId = select.getClientId(facesContext);
-    final String fieldId = select.getFieldId(facesContext);
-    final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, select);
-    final boolean disabled = !items.iterator().hasNext() || select.isDisabled() || select.isReadonly();
-    final Markup markup = select.getMarkup();
-    Integer size = select.getSize();
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
+    final boolean disabled = !items.iterator().hasNext() || component.isDisabled() || component.isReadonly();
+    final Markup markup = component.getMarkup();
+    Integer size = component.getSize();
     size = Math.max(size != null ? size : items.size(), 2); // must be > 1
 
     writer.startElement(HtmlElements.SELECT);
     writer.writeIdAttribute(fieldId);
     writer.writeNameAttribute(clientId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
-    writer.writeAttribute(HtmlAttributes.READONLY, select.isReadonly());
-    writer.writeAttribute(HtmlAttributes.REQUIRED, select.isRequired());
-    HtmlRendererUtils.renderFocus(clientId, select.isFocus(), ComponentUtils.isError(select), facesContext, writer);
+    writer.writeAttribute(HtmlAttributes.READONLY, component.isReadonly());
+    writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
 
-    writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
 
     writer.writeClassAttribute(
         TobagoClass.SELECT_ONE_LISTBOX,
-        TobagoClass.SELECT_ONE_LISTBOX.createMarkup(select.getMarkup()),
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(select)),
+        TobagoClass.SELECT_ONE_LISTBOX.createMarkup(component.getMarkup()),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
         BootstrapClass.FORM_CONTROL,
-        select.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     writer.writeAttribute(HtmlAttributes.SIZE, size);
-    HtmlRendererUtils.renderSelectItems(select, TobagoClass.SELECT_ONE_LISTBOX__OPTION, items, select.getValue(),
-        (String) select.getSubmittedValue(), writer, facesContext);
+    HtmlRendererUtils.renderSelectItems(component, TobagoClass.SELECT_ONE_LISTBOX__OPTION, items, component.getValue(),
+        (String) component.getSubmittedValue(), writer, facesContext);
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectOneListbox select = (AbstractUISelectOneListbox) component;
 
     writer.endElement(HtmlElements.SELECT);
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUISelectOneListbox select = (AbstractUISelectOneListbox) component;
-    return select.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioInsideCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioInsideCommandRenderer.java
index 005b03b..6c0a0d3 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioInsideCommandRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioInsideCommandRenderer.java
@@ -28,15 +28,15 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SelectOneRadioInsideCommandRenderer extends SelectOneRadioRenderer {
+public class SelectOneRadioInsideCommandRenderer<T extends AbstractUISelectOneRadio> extends SelectOneRadioRenderer<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeBeginField(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     encodeEndField(facesContext, component);
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
index 21b5ec2..8a9867d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRadioRenderer.java
@@ -36,12 +36,11 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 import java.io.IOException;
 
-public class SelectOneRadioRenderer extends SelectOneRendererBase {
+public class SelectOneRadioRenderer<T extends AbstractUISelectOneRadio> extends SelectOneRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -49,36 +48,33 @@ public class SelectOneRadioRenderer extends SelectOneRendererBase {
   }
 
   @Override
-  protected void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISelectOneRadio select = (AbstractUISelectOneRadio) component;
-    final AbstractUISelectReference reference = select.getRenderRangeReference();
+  protected void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
+    final AbstractUISelectReference reference = component.getRenderRangeReference();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String id = select.getClientId(facesContext);
-    final String referenceId = reference != null ? reference.getClientId(facesContext) : id;
-    final Iterable<SelectItem> items = SelectItemUtils.getItemIterator(facesContext, select);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, select);
-    final boolean disabled = select.isDisabled();
-    final boolean readonly = select.isReadonly();
-    final boolean required = select.isRequired();
-    final boolean inline = select.isInline();
-    final Markup markup = select.getMarkup();
+    final String id = component.getClientId(facesContext);
+//    final String referenceId = reference != null ? reference.getClientId(facesContext) : id;
+    final Iterable<SelectItem> items = SelectItemUtils.getItemIterator(facesContext, component);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+    final boolean disabled = component.isDisabled();
+    final boolean readonly = component.isReadonly();
+    final boolean required = component.isRequired();
+    final boolean inline = component.isInline();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(getOuterHtmlTag());
     writer.writeClassAttribute(
         TobagoClass.SELECT_ONE_RADIO,
         TobagoClass.SELECT_ONE_RADIO.createMarkup(markup),
         inline ? TobagoClass.SELECT_ONE_RADIO__INLINE : null,
-        select.getCustomClass());
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, select);
-    if (title != null) {
-      writer.writeAttribute(HtmlAttributes.TITLE, title, true);
-    }
+        component.getCustomClass());
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+    writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     boolean first = true;
-    final Object value = select.getValue();
-    final String submittedValue = (String) select.getSubmittedValue();
+    final Object value = component.getValue();
+    final String submittedValue = (String) component.getSubmittedValue();
     int i = 0;
-    final int[] renderRange = getRenderRangeList(select, reference);
+    final int[] renderRange = getRenderRangeList(component, reference);
     for (final SelectItem item : items) {
       if (renderRange == null || ArrayUtils.contains(renderRange, i)) {
         final boolean itemDisabled = item.isDisabled() || disabled;
@@ -90,7 +86,7 @@ public class SelectOneRadioRenderer extends SelectOneRendererBase {
         writer.startElement(HtmlElements.INPUT);
         writer.writeClassAttribute(BootstrapClass.FORM_CHECK_INPUT);
         writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.RADIO);
-        final String formattedValue = ComponentUtils.getFormattedValue(facesContext, select, item.getValue());
+        final String formattedValue = ComponentUtils.getFormattedValue(facesContext, component, item.getValue());
         final boolean checked;
         if (submittedValue == null) {
           checked = ObjectUtils.equals(item.getValue(), value);
@@ -105,16 +101,16 @@ public class SelectOneRadioRenderer extends SelectOneRendererBase {
         writer.writeAttribute(HtmlAttributes.READONLY, readonly);
         writer.writeAttribute(HtmlAttributes.REQUIRED, required);
         if (first) {
-          HtmlRendererUtils.renderFocus(id, select.isFocus(), ComponentUtils.isError(select), facesContext, writer);
+          HtmlRendererUtils.renderFocus(id, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
           first = false;
         }
-        writer.writeAttribute(HtmlAttributes.TABINDEX, select.getTabIndex());
+        writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
         writer.endElement(HtmlElements.INPUT);
 
         writer.startElement(HtmlElements.LABEL);
         writer.writeClassAttribute(
             BootstrapClass.FORM_CHECK_LABEL,
-            getCssItems(facesContext, select));
+            getCssItems(facesContext, component));
         writer.writeAttribute(HtmlAttributes.FOR, itemId, false);
         if (item instanceof org.apache.myfaces.tobago.model.SelectItem) {
           final org.apache.myfaces.tobago.model.SelectItem tobagoItem =
@@ -147,13 +143,12 @@ public class SelectOneRadioRenderer extends SelectOneRendererBase {
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUISelectOneRadio select = (AbstractUISelectOneRadio) component;
 
     writer.endElement(getOuterHtmlTag());
 
-    encodeBehavior(writer, facesContext, select);
+    encodeBehavior(writer, facesContext, component);
   }
 
   protected HtmlElements getOuterHtmlTag() {
@@ -165,7 +160,7 @@ public class SelectOneRadioRenderer extends SelectOneRendererBase {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
+  protected String getFieldId(final FacesContext facesContext, final T component) {
     return component.getClientId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java
index a77b1ee..a8453cd 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneRendererBase.java
@@ -24,30 +24,27 @@ import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.lang.invoke.MethodHandles;
 
-public abstract class SelectOneRendererBase extends MessageLayoutRendererBase {
+public abstract class SelectOneRendererBase<T extends AbstractUISelectOneBase> extends MessageLayoutRendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
-    final AbstractUISelectOneBase select = (AbstractUISelectOneBase) component;
-
-    final String clientId = select.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final Object newValue =
         facesContext.getExternalContext().getRequestParameterMap().get(clientId);
     if (LOG.isDebugEnabled()) {
       LOG.debug("decode: key='" + clientId + "' value='" + newValue + "'");
     }
-    select.setSubmittedValue(newValue);
+    component.setSubmittedValue(newValue);
 
-    decodeClientBehaviors(facesContext, select);
+    decodeClientBehaviors(facesContext, component);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectReferenceRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectReferenceRenderer.java
index 80ad934..fbd146a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectReferenceRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectReferenceRenderer.java
@@ -27,15 +27,14 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SelectReferenceRenderer extends RendererBase {
+public class SelectReferenceRenderer<T extends AbstractUISelectReference> extends RendererBase<T> {
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISelectReference reference = (AbstractUISelectReference) component;
-    final UIComponent select = component.findComponent(reference.getFor());
+    final UIComponent select = component.findComponent(component.getFor());
     final RenderRange range = (RenderRange) select;
-    range.setRenderRangeReference(reference);
+    range.setRenderRangeReference(component);
 
     select.encodeAll(facesContext);
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorInsideCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorInsideCommandRenderer.java
index f27e04f..d0e047e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorInsideCommandRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorInsideCommandRenderer.java
@@ -25,24 +25,22 @@ import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SeparatorInsideCommandRenderer extends SeparatorRenderer {
+public class SeparatorInsideCommandRenderer<T extends AbstractUISeparator> extends SeparatorRenderer<T> {
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISeparator separator = (AbstractUISeparator) component;
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String clientId = separator.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
 
     writer.startElement(HtmlElements.DIV);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
         TobagoClass.SEPARATOR,
         BootstrapClass.DROPDOWN_DIVIDER,
-        separator.getCustomClass());
+        component.getCustomClass());
     writer.endElement(HtmlElements.DIV);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorRenderer.java
index bc0c8b4..f5995fb 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SeparatorRenderer.java
@@ -33,24 +33,23 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class SeparatorRenderer extends RendererBase {
+public class SeparatorRenderer<T extends AbstractUISeparator> extends RendererBase<T> {
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISeparator separator = (AbstractUISeparator) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String clientId = separator.getClientId(facesContext);
-    final String label = getLabel(separator);
-    final Markup markup = separator.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final String label = getLabel(component);
+    final Markup markup = component.getMarkup();
 
     if (label != null) {
       writer.startElement(HtmlElements.P);
       writer.writeIdAttribute(clientId);
       writer.writeClassAttribute(
           TobagoClass.SEPARATOR,
-          TobagoClass.SEPARATOR.createMarkup(separator.getMarkup()),
-          separator.getCustomClass());
+          TobagoClass.SEPARATOR.createMarkup(component.getMarkup()),
+          component.getCustomClass());
       writer.writeText(label);
       writer.endElement(HtmlElements.P);
     } else {
@@ -58,8 +57,8 @@ public class SeparatorRenderer extends RendererBase {
       writer.writeIdAttribute(clientId);
       writer.writeClassAttribute(
           TobagoClass.SEPARATOR,
-          TobagoClass.SEPARATOR.createMarkup(separator.getMarkup()),
-          separator.getCustomClass());
+          TobagoClass.SEPARATOR.createMarkup(component.getMarkup()),
+          component.getCustomClass());
       writer.endElement(HtmlElements.HR);
     }
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetPageCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetPageCommandRenderer.java
index 72c43e9..05f62c3 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetPageCommandRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetPageCommandRenderer.java
@@ -19,5 +19,7 @@
 
 package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
-public class SheetPageCommandRenderer extends LinkRenderer {
+import org.apache.myfaces.tobago.internal.component.AbstractUILink;
+
+public class SheetPageCommandRenderer<T extends AbstractUILink> extends LinkRenderer<T> {
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
index 0abd6c7..669c2d2 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
@@ -91,7 +91,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
-public class SheetRenderer extends RendererBase {
+public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -103,15 +103,14 @@ public class SheetRenderer extends RendererBase {
   private static final String SUFFIX_PAGE_ACTION = "pageAction";
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
 
-    final AbstractUISheet sheet = (AbstractUISheet) component;
-    final List<AbstractUIColumnBase> columns = sheet.getAllColumns();
-    final String clientId = sheet.getClientId(facesContext);
+    final List<AbstractUIColumnBase> columns = component.getAllColumns();
+    final String clientId = component.getClientId(facesContext);
 
     String key = clientId + SUFFIX_WIDTHS;
     final Map<String, String> requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
-    final SheetState state = sheet.getState();
+    final SheetState state = component.getState();
     if (requestParameterMap.containsKey(key)) {
       final String widths = requestParameterMap.get(key);
       ensureColumnWidthsSize(state.getColumnWidths(), columns, JsonUtils.decodeIntegerArray(widths));
@@ -131,7 +130,7 @@ public class SheetRenderer extends RendererBase {
         selectedRows = Collections.emptyList();
       }
 
-      ComponentUtils.setAttribute(sheet, Attributes.selectedListString, selectedRows);
+      ComponentUtils.setAttribute(component, Attributes.selectedListString, selectedRows);
     }
 
     final String value
@@ -139,9 +138,9 @@ public class SheetRenderer extends RendererBase {
     if (value != null) {
       state.getScrollPosition().update(value);
     }
-    RenderUtils.decodedStateOfTreeData(facesContext, sheet);
+    RenderUtils.decodedStateOfTreeData(facesContext, component);
 
-    decodeSheetAction(facesContext, sheet);
+    decodeSheetAction(facesContext, component);
     decodeColumnAction(facesContext, columns);
 /* this will be done by the javax.faces.component.UIData.processDecodes() because these are facets.
     for (UIComponent facet : sheet.getFacets().values()) {
@@ -224,19 +223,18 @@ public class SheetRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISheet sheet = (AbstractUISheet) component;
-    final String sheetId = sheet.getClientId(facesContext);
-    final Markup markup = sheet.getMarkup();
+    final String sheetId = component.getClientId(facesContext);
+    final Markup markup = component.getMarkup();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUIReload reload = ComponentUtils.getReloadFacet(sheet);
+    final AbstractUIReload reload = ComponentUtils.getReloadFacet(component);
 
-    UIComponent header = sheet.getHeader();
+    UIComponent header = component.getHeader();
     if (header == null) {
       header = ComponentUtils.createComponent(facesContext, Tags.panel.componentType(), null, "_header");
       header.setTransient(true);
-      final List<AbstractUIColumnBase> columns = sheet.getAllColumns();
+      final List<AbstractUIColumnBase> columns = component.getAllColumns();
       int i = 0;
       for (final AbstractUIColumnBase column : columns) {
         if (!(column instanceof AbstractUIRow)) {
@@ -261,40 +259,39 @@ public class SheetRenderer extends RendererBase {
         }
         i++;
       }
-      sheet.setHeader(header);
+      component.setHeader(header);
     }
-    sheet.init(facesContext);
+    component.init(facesContext);
 
     // Outer sheet div
     writer.startElement(HtmlElements.TOBAGO_SHEET);
     writer.writeIdAttribute(sheetId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, sheet);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeClassAttribute(
-        sheet.getCustomClass(),
+        component.getCustomClass(),
         TobagoClass.SHEET.createMarkup(markup),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
     if (reload != null && reload.isRendered()) {
       writer.writeAttribute(DataAttributes.RELOAD, reload.getFrequency());
     }
-    writer.writeAttribute(DataAttributes.SELECTION_MODE, sheet.getSelectable().name(), false);
-    writer.writeAttribute(DataAttributes.FIRST, Integer.toString(sheet.getFirst()), false);
-    writer.writeAttribute(CustomAttributes.ROWS, sheet.getRows());
-    writer.writeAttribute(CustomAttributes.ROW_COUNT, Integer.toString(sheet.getRowCount()), false);
-    writer.writeAttribute(CustomAttributes.LAZY, sheet.isLazy());
-    writer.writeAttribute(CustomAttributes.LAZY_UPDATE, sheet.isLazy() && AjaxUtils.isAjaxRequest(facesContext));
-
-    final boolean autoLayout = sheet.isAutoLayout();
+    writer.writeAttribute(DataAttributes.SELECTION_MODE, component.getSelectable().name(), false);
+    writer.writeAttribute(DataAttributes.FIRST, Integer.toString(component.getFirst()), false);
+    writer.writeAttribute(CustomAttributes.ROWS, component.getRows());
+    writer.writeAttribute(CustomAttributes.ROW_COUNT, Integer.toString(component.getRowCount()), false);
+    writer.writeAttribute(CustomAttributes.LAZY, component.isLazy());
+    writer.writeAttribute(CustomAttributes.LAZY_UPDATE, component.isLazy() && AjaxUtils.isAjaxRequest(facesContext));
+
+    final boolean autoLayout = component.isAutoLayout();
     if (!autoLayout) {
-      writer.writeAttribute(DataAttributes.LAYOUT, JsonUtils.encode(sheet.getColumnLayout(), "columns"), true);
+      writer.writeAttribute(DataAttributes.LAYOUT, JsonUtils.encode(component.getColumnLayout(), "columns"), true);
     }
 
-    encodeBehavior(writer, facesContext, sheet);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISheet sheet = (AbstractUISheet) component;
-    for (final UIComponent child : sheet.getChildren()) {
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
+    for (final UIComponent child : component.getChildren()) {
       if (child instanceof AbstractUIStyle) {
         child.encodeAll(facesContext);
       }
@@ -302,20 +299,19 @@ public class SheetRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent uiComponent) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISheet sheet = (AbstractUISheet) uiComponent;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String sheetId = sheet.getClientId(facesContext);
-    final Selectable selectable = sheet.getSelectable();
+    final String sheetId = component.getClientId(facesContext);
+    final Selectable selectable = component.getSelectable();
     final Application application = facesContext.getApplication();
-    final SheetState state = sheet.getSheetState(facesContext);
-    final List<Integer> columnWidths = sheet.getState().getColumnWidths();
-    final boolean definedColumnWidths = sheet.getState().isDefinedColumnWidths();
-    final List<Integer> selectedRows = getSelectedRows(sheet, state);
-    final List<AbstractUIColumnBase> columns = sheet.getAllColumns();
-    final boolean autoLayout = sheet.isAutoLayout();
+    final SheetState state = component.getSheetState(facesContext);
+    final List<Integer> columnWidths = component.getState().getColumnWidths();
+    final boolean definedColumnWidths = component.getState().isDefinedColumnWidths();
+    final List<Integer> selectedRows = getSelectedRows(component, state);
+    final List<AbstractUIColumnBase> columns = component.getAllColumns();
+    final boolean autoLayout = component.isAutoLayout();
 
     ensureColumnWidthsSize(columnWidths, columns, Collections.emptyList());
 
@@ -337,8 +333,8 @@ public class SheetRenderer extends RendererBase {
     }
 
     encodeHiddenInput(writer,
-        sheet.getState().getScrollPosition().encode(),
-        sheet.getClientId(facesContext) + SUFFIX_SCROLL_POSITION);
+        component.getState().getScrollPosition().encode(),
+        component.getClientId(facesContext) + SUFFIX_SCROLL_POSITION);
 
     if (selectable != Selectable.none) {
       encodeHiddenInput(writer,
@@ -346,24 +342,24 @@ public class SheetRenderer extends RendererBase {
           sheetId + SUFFIX_SELECTED);
     }
 
-    if (sheet.isLazy()) {
+    if (component.isLazy()) {
       encodeHiddenInput(writer, null, sheetId + SUFFIX_LAZY);
     }
 
-    final List<Integer> expandedValue = sheet.isTreeModel() ? new ArrayList<>() : null;
+    final List<Integer> expandedValue = component.isTreeModel() ? new ArrayList<>() : null;
 
-    encodeTableBody(facesContext, sheet, writer, sheetId, selectable, columnWidths, selectedRows, columns, autoLayout,
+    encodeTableBody(facesContext, component, writer, sheetId, selectable, columnWidths, selectedRows, columns, autoLayout,
         expandedValue);
 
-    if (sheet.isPagingVisible()) {
+    if (component.isPagingVisible()) {
       writer.startElement(HtmlElements.FOOTER);
       writer.writeClassAttribute(TobagoClass.SHEET__FOOTER);
 
       // show row range
-      final Markup showRowRange = markupForLeftCenterRight(sheet.getShowRowRange());
+      final Markup showRowRange = markupForLeftCenterRight(component.getShowRowRange());
       if (showRowRange != Markup.NULL) {
         final AbstractUILink command
-            = ensurePagingCommand(facesContext, sheet, Facets.pagerRow.name(), SheetAction.toRow.name(), false);
+            = ensurePagingCommand(facesContext, component, Facets.pagerRow.name(), SheetAction.toRow.name(), false);
         final String pagerCommandId = command.getClientId(facesContext);
 
         writer.startElement(HtmlElements.UL);
@@ -375,13 +371,13 @@ public class SheetRenderer extends RendererBase {
             ResourceUtils.getString(facesContext, "sheet.setRow"), true);
         writer.startElement(HtmlElements.SPAN);
         writer.writeClassAttribute(TobagoClass.SHEET__PAGING_TEXT, BootstrapClass.PAGE_LINK);
-        if (sheet.getRowCount() != 0) {
+        if (component.getRowCount() != 0) {
           final Locale locale = facesContext.getViewRoot().getLocale();
-          final int first = sheet.getFirst() + 1;
-          final int last1 = sheet.hasRowCount()
-              ? sheet.getLastRowIndexOfCurrentPage()
+          final int first = component.getFirst() + 1;
+          final int last1 = component.hasRowCount()
+              ? component.getLastRowIndexOfCurrentPage()
               : -1;
-          final boolean unknown = !sheet.hasRowCount();
+          final boolean unknown = !component.hasRowCount();
           final String key; // plural
           if (unknown) {
             key = first == last1 ? "sheet.rowX" : "sheet.rowXtoY";
@@ -389,7 +385,7 @@ public class SheetRenderer extends RendererBase {
             key = first == last1 ? "sheet.rowXofZ" : "sheet.rowXtoYofZ";
           }
           final String inputMarker = "{#}";
-          final Object[] args = {inputMarker, last1 == -1 ? "?" : last1, unknown ? "" : sheet.getRowCount()};
+          final Object[] args = {inputMarker, last1 == -1 ? "?" : last1, unknown ? "" : component.getRowCount()};
           final MessageFormat detail = new MessageFormat(ResourceUtils.getString(facesContext, key), locale);
           final String formatted = detail.format(args);
           final int pos = formatted.indexOf(inputMarker);
@@ -406,7 +402,7 @@ public class SheetRenderer extends RendererBase {
             writer.writeClassAttribute(TobagoClass.SHEET__PAGING_INPUT);
             writer.writeAttribute(HtmlAttributes.VALUE, first);
             if (!unknown) {
-              writer.writeAttribute(HtmlAttributes.MAXLENGTH, Integer.toString(sheet.getRowCount()).length());
+              writer.writeAttribute(HtmlAttributes.MAXLENGTH, Integer.toString(component.getRowCount()).length());
             }
             writer.endElement(HtmlElements.INPUT);
             writer.writeText(formatted.substring(pos + inputMarker.length()));
@@ -414,47 +410,47 @@ public class SheetRenderer extends RendererBase {
             writer.writeText(formatted);
           }
         }
-        ComponentUtils.removeFacet(sheet, Facets.pagerRow);
+        ComponentUtils.removeFacet(component, Facets.pagerRow);
         writer.endElement(HtmlElements.SPAN);
         writer.endElement(HtmlElements.LI);
         writer.endElement(HtmlElements.UL);
       }
 
       // show direct links
-      final Markup showDirectLinks = markupForLeftCenterRight(sheet.getShowDirectLinks());
+      final Markup showDirectLinks = markupForLeftCenterRight(component.getShowDirectLinks());
       if (showDirectLinks != Markup.NULL) {
         writer.startElement(HtmlElements.UL);
         writer.writeClassAttribute(TobagoClass.SHEET__PAGING, TobagoClass.SHEET__PAGING.createMarkup(showDirectLinks),
             BootstrapClass.PAGINATION);
-        if (sheet.isShowDirectLinksArrows()) {
-          final boolean disabled = sheet.isAtBeginning();
-          encodeLink(facesContext, sheet, application, disabled, SheetAction.first, null, Icons.STEP_BACKWARD, null);
-          encodeLink(facesContext, sheet, application, disabled, SheetAction.prev, null, Icons.BACKWARD, null);
+        if (component.isShowDirectLinksArrows()) {
+          final boolean disabled = component.isAtBeginning();
+          encodeLink(facesContext, component, application, disabled, SheetAction.first, null, Icons.STEP_BACKWARD, null);
+          encodeLink(facesContext, component, application, disabled, SheetAction.prev, null, Icons.BACKWARD, null);
         }
-        encodeDirectPagingLinks(facesContext, application, sheet);
-        if (sheet.isShowDirectLinksArrows()) {
-          final boolean disabled = sheet.isAtEnd();
-          encodeLink(facesContext, sheet, application, disabled, SheetAction.next, null, Icons.FORWARD, null);
-          encodeLink(facesContext, sheet, application, disabled || !sheet.hasRowCount(), SheetAction.last, null,
+        encodeDirectPagingLinks(facesContext, application, component);
+        if (component.isShowDirectLinksArrows()) {
+          final boolean disabled = component.isAtEnd();
+          encodeLink(facesContext, component, application, disabled, SheetAction.next, null, Icons.FORWARD, null);
+          encodeLink(facesContext, component, application, disabled || !component.hasRowCount(), SheetAction.last, null,
               Icons.STEP_FORWARD, null);
         }
         writer.endElement(HtmlElements.UL);
       }
 
       // show page range
-      final Markup showPageRange = markupForLeftCenterRight(sheet.getShowPageRange());
+      final Markup showPageRange = markupForLeftCenterRight(component.getShowPageRange());
       if (showPageRange != Markup.NULL) {
         final AbstractUILink command
-            = ensurePagingCommand(facesContext, sheet, Facets.pagerPage.name(), SheetAction.toPage.name(), false);
+            = ensurePagingCommand(facesContext, component, Facets.pagerPage.name(), SheetAction.toPage.name(), false);
         final String pagerCommandId = command.getClientId(facesContext);
 
         writer.startElement(HtmlElements.UL);
         writer.writeClassAttribute(TobagoClass.SHEET__PAGING, TobagoClass.SHEET__PAGING.createMarkup(showPageRange),
             BootstrapClass.PAGINATION);
-        if (sheet.isShowPageRangeArrows()) {
-          final boolean disabled = sheet.isAtBeginning();
-          encodeLink(facesContext, sheet, application, disabled, SheetAction.first, null, Icons.STEP_BACKWARD, null);
-          encodeLink(facesContext, sheet, application, disabled, SheetAction.prev, null, Icons.BACKWARD, null);
+        if (component.isShowPageRangeArrows()) {
+          final boolean disabled = component.isAtBeginning();
+          encodeLink(facesContext, component, application, disabled, SheetAction.first, null, Icons.STEP_BACKWARD, null);
+          encodeLink(facesContext, component, application, disabled, SheetAction.prev, null, Icons.BACKWARD, null);
         }
         writer.startElement(HtmlElements.LI);
         writer.writeClassAttribute(BootstrapClass.PAGE_ITEM);
@@ -462,11 +458,11 @@ public class SheetRenderer extends RendererBase {
         writer.writeClassAttribute(TobagoClass.SHEET__PAGING_TEXT, BootstrapClass.PAGE_LINK);
         writer.writeAttribute(HtmlAttributes.TITLE,
             ResourceUtils.getString(facesContext, "sheet.setPage"), true);
-        if (sheet.getRowCount() != 0) {
+        if (component.getRowCount() != 0) {
           final Locale locale = facesContext.getViewRoot().getLocale();
-          final int first = sheet.getCurrentPage() + 1;
-          final boolean unknown = !sheet.hasRowCount();
-          final int pages = unknown ? -1 : sheet.getPages();
+          final int first = component.getCurrentPage() + 1;
+          final boolean unknown = !component.hasRowCount();
+          final int pages = unknown ? -1 : component.getPages();
           final String key;
           if (unknown) {
             key = first == pages ? "sheet.pageX" : "sheet.pageXtoY";
@@ -499,13 +495,13 @@ public class SheetRenderer extends RendererBase {
             writer.writeText(formatted);
           }
         }
-        ComponentUtils.removeFacet(sheet, Facets.pagerPage);
+        ComponentUtils.removeFacet(component, Facets.pagerPage);
         writer.endElement(HtmlElements.SPAN);
         writer.endElement(HtmlElements.LI);
-        if (sheet.isShowPageRangeArrows()) {
-          final boolean disabled = sheet.isAtEnd();
-          encodeLink(facesContext, sheet, application, disabled, SheetAction.next, null, Icons.FORWARD, null);
-          encodeLink(facesContext, sheet, application, disabled || !sheet.hasRowCount(), SheetAction.last, null,
+        if (component.isShowPageRangeArrows()) {
+          final boolean disabled = component.isAtEnd();
+          encodeLink(facesContext, component, application, disabled, SheetAction.next, null, Icons.FORWARD, null);
+          encodeLink(facesContext, component, application, disabled || !component.hasRowCount(), SheetAction.last, null,
               Icons.STEP_FORWARD, null);
         }
         writer.endElement(HtmlElements.UL);
@@ -514,7 +510,7 @@ public class SheetRenderer extends RendererBase {
       writer.endElement(HtmlElements.FOOTER);
     }
 
-    if (sheet.isTreeModel()) {
+    if (component.isTreeModel()) {
       writer.startElement(HtmlElements.INPUT);
       writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
       final String expandedId = sheetId + ComponentUtils.SUB_SEPARATOR + AbstractUIData.SUFFIX_EXPANDED;
@@ -526,9 +522,9 @@ public class SheetRenderer extends RendererBase {
     }
 
     writer.endElement(HtmlElements.TOBAGO_SHEET);
-    UIComponent header = sheet.getHeader();
+    UIComponent header = component.getHeader();
     if (header.isTransient()) {
-      sheet.getFacets().remove("header");
+      component.getFacets().remove("header");
     }
   }
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SplitLayoutRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SplitLayoutRenderer.java
index 91c8044..b26d8f4 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SplitLayoutRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SplitLayoutRenderer.java
@@ -35,7 +35,6 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
@@ -46,14 +45,14 @@ import java.lang.invoke.MethodHandles;
  * </p>
  */
 @Preliminary
-public class SplitLayoutRenderer extends RendererBase {
+public class SplitLayoutRenderer<T extends AbstractUISplitLayout> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   private static final String SUFFIX_SIZES = ComponentUtils.SUB_SEPARATOR + "sizes";
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     final String sourceId = facesContext.getExternalContext().getRequestParameterMap().get("javax.faces.source");
     final String clientId = component.getClientId() + SUFFIX_SIZES;
     if (clientId.equals(sourceId)) {
@@ -66,29 +65,27 @@ public class SplitLayoutRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISplitLayout splitLayout = (AbstractUISplitLayout) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Markup markup = splitLayout.getMarkup();
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.TOBAGO_SPLIT_LAYOUT);
-    writer.writeIdAttribute(splitLayout.getClientId(facesContext));
+    writer.writeIdAttribute(component.getClientId(facesContext));
     writer.writeClassAttribute(
-        splitLayout.isHorizontal() ? BootstrapClass.FLEX_ROW : BootstrapClass.FLEX_COLUMN,
+        component.isHorizontal() ? BootstrapClass.FLEX_ROW : BootstrapClass.FLEX_COLUMN,
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
     writer.writeAttribute(CustomAttributes.ORIENTATION,
-        splitLayout.isHorizontal() ? Orientation.HORIZONTAL : Orientation.VERTICAL, false);
+        component.isHorizontal() ? Orientation.HORIZONTAL : Orientation.VERTICAL, false);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUISplitLayout splitLayout = (AbstractUISplitLayout) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.INPUT);
-    writer.writeNameAttribute(splitLayout.getClientId(facesContext) + SUFFIX_SIZES);
+    writer.writeNameAttribute(component.getClientId(facesContext) + SUFFIX_SIZES);
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
 //    writer.writeAttribute(HtmlAttributes.VALUE, sizes);
     writer.endElement(HtmlElements.INPUT);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StarsRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StarsRenderer.java
index 1657cd4..677c250 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StarsRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StarsRenderer.java
@@ -29,11 +29,10 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class StarsRenderer extends MessageLayoutRendererBase {
+public class StarsRenderer<T extends AbstractUIStars> extends MessageLayoutRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
@@ -41,32 +40,31 @@ public class StarsRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeBeginField(FacesContext facesContext, UIComponent component) throws IOException {
+  protected void encodeBeginField(FacesContext facesContext, T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUIStars stars = (AbstractUIStars) component;
-    final String clientId = stars.getClientId(facesContext);
-    final String fieldId = stars.getFieldId(facesContext);
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
     final String hiddenInputId = clientId + ComponentUtils.SUB_SEPARATOR + "input";
     final String sliderId = clientId + ComponentUtils.SUB_SEPARATOR + "slider";
-    final int value = stars.getRangeValue();
-    final int max = stars.getRangeMax();
-    final Double placeholder = stars.getPlaceholder();
-    final boolean readonly = stars.isReadonly();
-    final boolean disabled = stars.isDisabled();
-    final boolean required = stars.isRequired();
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, stars);
-
-    final String sliderValue = stars.getSubmittedValue() != null
-        ? (String) stars.getSubmittedValue() : String.valueOf(value);
+    final int value = component.getRangeValue();
+    final int max = component.getRangeMax();
+    final Double placeholder = component.getPlaceholder();
+    final boolean readonly = component.isReadonly();
+    final boolean disabled = component.isDisabled();
+    final boolean required = component.isRequired();
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
+
+    final String sliderValue = component.getSubmittedValue() != null
+        ? (String) component.getSubmittedValue() : String.valueOf(value);
     final String hiddenInputValue = required && "0".equals(sliderValue) ? null : sliderValue;
 
     writer.startElement(HtmlElements.DIV);
     writer.writeIdAttribute(fieldId);
     writer.writeClassAttribute(
         TobagoClass.STARS,
-        TobagoClass.STARS.createMarkup(stars.getMarkup()),
-        stars.getCustomClass());
+        TobagoClass.STARS.createMarkup(component.getMarkup()),
+        component.getCustomClass());
 
     // The hidden input must be used to submit the rating. The 'required' attribute is not allowed on slider component.
     writer.startElement(HtmlElements.INPUT);
@@ -96,12 +94,12 @@ public class StarsRenderer extends MessageLayoutRendererBase {
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
     writer.writeAttribute(HtmlAttributes.REQUIRED, required);
-    HtmlRendererUtils.renderFocus(clientId, stars.isFocus(), ComponentUtils.isError(stars), facesContext, writer);
-    writer.writeAttribute(HtmlAttributes.TABINDEX, stars.getTabIndex());
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
     writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     writer.endElement(HtmlElements.INPUT);
 
-    encodeBehavior(writer, facesContext, stars);
+    encodeBehavior(writer, facesContext, component);
 
     writer.startElement(HtmlElements.DIV);
     writer.writeClassAttribute(TobagoClass.STARS__FOCUS_BOX);
@@ -123,14 +121,13 @@ public class StarsRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  protected void encodeEndField(FacesContext facesContext, UIComponent component) throws IOException {
+  protected void encodeEndField(FacesContext facesContext, T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.DIV);
   }
 
   @Override
-  protected String getFieldId(FacesContext facesContext, UIComponent component) {
-    final AbstractUIStars stars = (AbstractUIStars) component;
-    return stars.getFieldId(facesContext);
+  protected String getFieldId(FacesContext facesContext, T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StyleRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StyleRenderer.java
index 6e20185..144f888 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StyleRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/StyleRenderer.java
@@ -35,19 +35,17 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class StyleRenderer extends RendererBase {
+public class StyleRenderer<T extends AbstractUIStyle> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUIStyle style = (AbstractUIStyle) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
-    final String file = style.getFile();
+    final String file = component.getFile();
     if (StringUtils.isNotBlank(file)) {
 
       writer.startElement(HtmlElements.LINK);
@@ -70,37 +68,37 @@ public class StyleRenderer extends RendererBase {
 
     } else {
 
-      final Measure width = style.getWidth();
-      final Measure height = style.getHeight();
-      final Measure minWidth = style.getMinWidth();
-      final Measure minHeight = style.getMinHeight();
-      final Measure maxWidth = style.getMaxWidth();
-      final Measure maxHeight = style.getMaxHeight();
-      final Measure left = style.getLeft();
-      final Measure right = style.getRight();
-      final Measure top = style.getTop();
-      final Measure bottom = style.getBottom();
-      final Measure paddingLeft = style.getPaddingLeft();
-      final Measure paddingRight = style.getPaddingRight();
-      final Measure paddingTop = style.getPaddingTop();
-      final Measure paddingBottom = style.getPaddingBottom();
-      final Measure marginLeft = style.getMarginLeft();
-      final Measure marginRight = style.getMarginRight();
-      final Measure marginTop = style.getMarginTop();
-      final Measure marginBottom = style.getMarginBottom();
-      final Overflow overflowX = style.getOverflowX();
-      final Overflow overflowY = style.getOverflowY();
-      final Display display = style.getDisplay();
-      final Position position = style.getPosition();
-      final TextAlign textAlign = style.getTextAlign();
-      final String backgroundImage = style.getBackgroundImage();
-      final Number flexGrow = style.getFlexGrow();
-      final Number flexShrink = style.getFlexShrink();
-      final Measure flexBasis = style.getFlexBasis();
-      final String gridTemplateColumns = style.getGridTemplateColumns();
-      final String gridTemplateRows = style.getGridTemplateRows();
-      final GridSpan gridColumn = style.getGridColumn();
-      final GridSpan gridRow = style.getGridRow();
+      final Measure width = component.getWidth();
+      final Measure height = component.getHeight();
+      final Measure minWidth = component.getMinWidth();
+      final Measure minHeight = component.getMinHeight();
+      final Measure maxWidth = component.getMaxWidth();
+      final Measure maxHeight = component.getMaxHeight();
+      final Measure left = component.getLeft();
+      final Measure right = component.getRight();
+      final Measure top = component.getTop();
+      final Measure bottom = component.getBottom();
+      final Measure paddingLeft = component.getPaddingLeft();
+      final Measure paddingRight = component.getPaddingRight();
+      final Measure paddingTop = component.getPaddingTop();
+      final Measure paddingBottom = component.getPaddingBottom();
+      final Measure marginLeft = component.getMarginLeft();
+      final Measure marginRight = component.getMarginRight();
+      final Measure marginTop = component.getMarginTop();
+      final Measure marginBottom = component.getMarginBottom();
+      final Overflow overflowX = component.getOverflowX();
+      final Overflow overflowY = component.getOverflowY();
+      final Display display = component.getDisplay();
+      final Position position = component.getPosition();
+      final TextAlign textAlign = component.getTextAlign();
+      final String backgroundImage = component.getBackgroundImage();
+      final Number flexGrow = component.getFlexGrow();
+      final Number flexShrink = component.getFlexShrink();
+      final Measure flexBasis = component.getFlexBasis();
+      final String gridTemplateColumns = component.getGridTemplateColumns();
+      final String gridTemplateRows = component.getGridTemplateRows();
+      final GridSpan gridColumn = component.getGridColumn();
+      final GridSpan gridRow = component.getGridRow();
 
       // todo: backgroundPosition and zIndex
 
@@ -138,12 +136,12 @@ public class StyleRenderer extends RendererBase {
 
         writer.startElement(HtmlElements.STYLE);
         writer.writeAttribute(HtmlAttributes.NONCE, Nonce.getNonce(facesContext), false);
-        writer.writeIdAttribute(style.getClientId(facesContext));
-        final String selector = style.getSelector();
+        writer.writeIdAttribute(component.getClientId(facesContext));
+        final String selector = component.getSelector();
         if (selector != null) {
           StyleRenderUtils.writeSelector(writer, selector);
         } else {
-          final String parentId = style.getParent().getClientId(facesContext);
+          final String parentId = component.getParent().getClientId(facesContext);
           StyleRenderUtils.writeIdSelector(writer, parentId);
         }
         writer.writeText("{");
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SubviewRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SubviewRenderer.java
index 010dbd1..261c541 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SubviewRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SubviewRenderer.java
@@ -23,25 +23,27 @@ import org.apache.myfaces.tobago.renderkit.RendererBase;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.faces.component.NamingContainer;
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 
-public class SubviewRenderer extends RendererBase {
+public class SubviewRenderer<T extends UIComponent & NamingContainer> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component)
+  public void encodeBeginInternal(final FacesContext facesContext, final T component)
       throws IOException {
-    LOG.debug("Subview component = {}", component.getClass().getName());
-    super.encodeBegin(facesContext, component);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Subview component = {}", component.getClass().getName());
+    }
+    super.encodeBeginInternal(facesContext, component);
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext,
-                        final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
   }
 
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SuggestRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SuggestRenderer.java
index 1fbc1c9..211be87 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SuggestRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SuggestRenderer.java
@@ -36,7 +36,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.el.MethodExpression;
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 import java.io.IOException;
@@ -46,14 +45,13 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-public class SuggestRenderer extends RendererBase {
+public class SuggestRenderer<T extends AbstractUISuggest> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUISuggest suggest = (AbstractUISuggest) component;
-    final String clientId = suggest.getClientId(facesContext);
+  public void decodeInternal(final FacesContext facesContext, final T component) {
+    final String clientId = component.getClientId(facesContext);
     final Map<String, String> requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
     if (requestParameterMap.containsKey(clientId)) {
       final String query = requestParameterMap.get(clientId);
@@ -61,22 +59,21 @@ public class SuggestRenderer extends RendererBase {
         LOG.debug("suggest query='{}'", query);
       }
       // XXX this is for the old way: for "suggestMethod"
-      final AbstractUIInput input = ComponentUtils.findAncestor(suggest, AbstractUIInput.class);
+      final AbstractUIInput input = ComponentUtils.findAncestor(component, AbstractUIInput.class);
       if (input != null) {
         input.setSubmittedValue(query);
       }
       // this is the new way: for select items
-      suggest.setQuery(query);
+      component.setQuery(query);
     }
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUISuggest suggest = (AbstractUISuggest) component;
-    final AbstractUIInput input = ComponentUtils.findAncestor(suggest, AbstractUIInput.class);
-    final MethodExpression suggestMethodExpression = suggest.getSuggestMethodExpression();
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
+    final AbstractUIInput input = ComponentUtils.findAncestor(component, AbstractUIInput.class);
+    final MethodExpression suggestMethodExpression = component.getSuggestMethodExpression();
 
-    int totalCount = suggest.getTotalCount();
+    int totalCount = component.getTotalCount();
     final String[] array;
 
     if (suggestMethodExpression != null && input != null) { // old way (deprecated)
@@ -93,7 +90,7 @@ public class SuggestRenderer extends RendererBase {
         array[i] = items.get(i).getLabel();
       }
     } else {
-      final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, suggest);
+      final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
 
       if (totalCount == -1 || items.size() < totalCount) {
         totalCount = items.size();
@@ -108,7 +105,7 @@ public class SuggestRenderer extends RendererBase {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.TOBAGO_SUGGEST);
-    final String clientId = suggest.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     writer.writeIdAttribute(clientId);
     if (input != null) {
       writer.writeAttribute(HtmlAttributes.FOR, input.getFieldId(facesContext), false);
@@ -116,12 +113,12 @@ public class SuggestRenderer extends RendererBase {
       LOG.error("No ancestor with type AbstractUIInput found for suggest id={}", clientId);
     }
 
-    writer.writeAttribute(CustomAttributes.MIN_CHARS, suggest.getMinimumCharacters());
-    writer.writeAttribute(CustomAttributes.DELAY, suggest.getDelay());
-    writer.writeAttribute(CustomAttributes.MAX_ITEMS, suggest.getMaximumItems());
-    writer.writeAttribute(CustomAttributes.UPDATE, suggest.isUpdate());
+    writer.writeAttribute(CustomAttributes.MIN_CHARS, component.getMinimumCharacters());
+    writer.writeAttribute(CustomAttributes.DELAY, component.getDelay());
+    writer.writeAttribute(CustomAttributes.MAX_ITEMS, component.getMaximumItems());
+    writer.writeAttribute(CustomAttributes.UPDATE, component.isUpdate());
     writer.writeAttribute(CustomAttributes.TOTAL_COUNT, totalCount);
-    writer.writeAttribute(CustomAttributes.LOCAL_MENU, suggest.isLocalMenu());
+    writer.writeAttribute(CustomAttributes.LOCAL_MENU, component.isLocalMenu());
     writer.writeAttribute(CustomAttributes.ITEMS, JsonUtils.encode(array), true);
 
     if (LOG.isDebugEnabled()) {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
index 407631d..df03fba 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
@@ -66,7 +66,8 @@ import java.util.Collections;
 import java.util.Map;
 
 @ListenerFor(systemEventClass = PostAddToViewEvent.class)
-public class TabGroupRenderer extends RendererBase implements ComponentSystemEventListener {
+public class TabGroupRenderer<T extends AbstractUITabGroup> extends RendererBase<T>
+    implements ComponentSystemEventListener {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -113,16 +114,16 @@ public class TabGroupRenderer extends RendererBase implements ComponentSystemEve
   }
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
-    final int oldIndex = ((AbstractUITabGroup) component).getRenderedIndex();
+    final int oldIndex = component.getRenderedIndex();
 
     final String clientId = component.getClientId(facesContext);
-    final Map parameters = facesContext.getExternalContext().getRequestParameterMap();
-    final String newValue = (String) parameters.get(clientId + INDEX_POSTFIX);
+    final Map<String, String> parameters = facesContext.getExternalContext().getRequestParameterMap();
+    final String newValue = parameters.get(clientId + INDEX_POSTFIX);
     try {
       final int newIndex = Integer.parseInt(newValue);
       if (newIndex != oldIndex) {
@@ -135,14 +136,13 @@ public class TabGroupRenderer extends RendererBase implements ComponentSystemEve
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent uiComponent) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T uiComponent) throws IOException {
 
-    final AbstractUITabGroup tabGroup = (AbstractUITabGroup) uiComponent;
-    final int selectedIndex = ensureRenderedSelectedIndex(facesContext, tabGroup);
-    final String clientId = tabGroup.getClientId(facesContext);
+    final int selectedIndex = ensureRenderedSelectedIndex(facesContext, uiComponent);
+    final String clientId = uiComponent.getClientId(facesContext);
     final String hiddenId = clientId + TabGroupRenderer.INDEX_POSTFIX;
-    final SwitchType switchType = tabGroup.getSwitchType();
-    final Markup markup = tabGroup.getMarkup();
+    final SwitchType switchType = uiComponent.getSwitchType();
+    final Markup markup = uiComponent.getMarkup();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.TOBAGO_TAB_GROUP);
@@ -150,12 +150,12 @@ public class TabGroupRenderer extends RendererBase implements ComponentSystemEve
     writer.writeClassAttribute(
         BootstrapClass.CARD,
         TobagoClass.TAB_GROUP.createMarkup(markup),
-        tabGroup.getCustomClass(),
+        uiComponent.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, tabGroup);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, uiComponent);
     writer.writeAttribute(CustomAttributes.SWITCH_TYPE, switchType.name(), false);
 
-    encodeBehavior(writer, facesContext, tabGroup);
+    encodeBehavior(writer, facesContext, uiComponent);
 
     writer.startElement(HtmlElements.INPUT);
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
@@ -164,11 +164,11 @@ public class TabGroupRenderer extends RendererBase implements ComponentSystemEve
     writer.writeIdAttribute(hiddenId);
     writer.endElement(HtmlElements.INPUT);
 
-    if (tabGroup.isShowNavigationBar()) {
-      encodeHeader(facesContext, writer, tabGroup, selectedIndex, switchType);
+    if (uiComponent.isShowNavigationBar()) {
+      encodeHeader(facesContext, writer, uiComponent, selectedIndex, switchType);
     }
 
-    encodeContent(facesContext, writer, tabGroup, selectedIndex, switchType);
+    encodeContent(facesContext, writer, uiComponent, selectedIndex, switchType);
 
     writer.endElement(HtmlElements.TOBAGO_TAB_GROUP);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java
index 5f42d3b..29e17e0 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java
@@ -34,27 +34,21 @@ import org.apache.myfaces.tobago.sanitizer.SanitizeMode;
 import org.apache.myfaces.tobago.sanitizer.Sanitizer;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import javax.faces.component.EditableValueHolder;
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.validator.LengthValidator;
 import javax.faces.validator.RegexValidator;
 import javax.faces.validator.Validator;
 import java.io.IOException;
-import java.lang.invoke.MethodHandles;
 
-public class TextareaRenderer extends MessageLayoutRendererBase {
+public class TextareaRenderer<T extends AbstractUITextarea> extends MessageLayoutRendererBase<T> {
 
   @Override
   public HtmlElements getComponentTag() {
     return HtmlElements.TOBAGO_TEXTAREA;
   }
 
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
   @Override
   protected void setSubmittedValue(
       final FacesContext facesContext, final EditableValueHolder component, final String newValue) {
@@ -77,50 +71,43 @@ public class TextareaRenderer extends MessageLayoutRendererBase {
   }
 
   @Override
-  public void encodeBeginField(final FacesContext facesContext, final UIComponent component) throws IOException {
-    if (!(component instanceof AbstractUITextarea)) {
-      LOG.error(
-          "Wrong type: Need " + AbstractUITextarea.class.getName() + ", but was " + component.getClass().getName());
-      return;
-    }
-
-    final AbstractUITextarea input = (AbstractUITextarea) component;
+  public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
     final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
-    final String clientId = input.getClientId(facesContext);
-    final String fieldId = input.getFieldId(facesContext);
+    final String clientId = component.getClientId(facesContext);
+    final String fieldId = component.getFieldId(facesContext);
+    final Integer rows = component.getRows();
+    final boolean readonly = component.isReadonly();
+    final boolean disabled = component.isDisabled();
+    final Markup markup = component.getMarkup();
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final Integer rows = input.getRows();
-    final boolean readonly = input.isReadonly();
-    final boolean disabled = input.isDisabled();
-    final Markup markup = input.getMarkup();
 
     writer.startElement(HtmlElements.TEXTAREA);
     writer.writeNameAttribute(clientId);
     writer.writeIdAttribute(fieldId);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, input);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeAttribute(HtmlAttributes.ROWS, rows);
     writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
-    writer.writeAttribute(HtmlAttributes.REQUIRED, input.isRequired());
-    writer.writeAttribute(HtmlAttributes.TABINDEX, input.getTabIndex());
+    writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
+    writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
 
-    if (input.getAccessKey() != null) {
-      writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(input.getAccessKey()), false);
-      AccessKeyLogger.addAccessKey(facesContext, input.getAccessKey(), clientId);
+    if (component.getAccessKey() != null) {
+      writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(component.getAccessKey()), false);
+      AccessKeyLogger.addAccessKey(facesContext, component.getAccessKey(), clientId);
     }
 
     writer.writeClassAttribute(
         TobagoClass.TEXTAREA,
-        TobagoClass.TEXTAREA.createMarkup(input.getMarkup()),
-        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(input)),
+        TobagoClass.TEXTAREA.createMarkup(component.getMarkup()),
+        BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
         BootstrapClass.FORM_CONTROL,
-        input.getCustomClass(),
+        component.getCustomClass(),
         markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
     int maxLength = 0;
     int minLength = 0;
     String pattern = null;
-    for (final Validator validator : input.getValidators()) {
+    for (final Validator validator : component.getValidators()) {
       if (validator instanceof LengthValidator) {
         final LengthValidator lengthValidator = (LengthValidator) validator;
         maxLength = lengthValidator.getMaximum();
@@ -140,16 +127,16 @@ public class TextareaRenderer extends MessageLayoutRendererBase {
       writer.writeAttribute(HtmlAttributes.PATTERN, pattern, true);
     }
 
-    HtmlRendererUtils.renderFocus(clientId, input.isFocus(), ComponentUtils.isError(input), facesContext, writer);
+    HtmlRendererUtils.renderFocus(clientId, component.isFocus(), ComponentUtils.isError(component), facesContext, writer);
 
-    final String placeholder = input.getPlaceholder();
+    final String placeholder = component.getPlaceholder();
     if (!disabled && !readonly && StringUtils.isNotBlank(placeholder)) {
       writer.writeAttribute(HtmlAttributes.PLACEHOLDER, placeholder, true);
     }
-    String currentValue = RenderUtils.currentValue(input);
+    String currentValue = RenderUtils.currentValue(component);
     if (currentValue != null) {
-      if (ComponentUtils.getDataAttribute(input, "html-editor") != null
-          && SanitizeMode.auto == input.getSanitize()) {
+      if (ComponentUtils.getDataAttribute(component, "html-editor") != null
+          && SanitizeMode.auto == component.getSanitize()) {
         final Sanitizer sanitizer = TobagoConfig.getInstance(facesContext).getSanitizer();
         currentValue = sanitizer.sanitize(currentValue);
       }
@@ -165,16 +152,15 @@ public class TextareaRenderer extends MessageLayoutRendererBase {
     }
 
     writer.endElement(HtmlElements.TEXTAREA);
-    encodeBehavior(writer, facesContext, input);
+    encodeBehavior(writer, facesContext, component);
   }
 
   @Override
-  protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
+  protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
   }
 
   @Override
-  protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUITextarea input = (AbstractUITextarea) component;
-    return input.getFieldId(facesContext);
+  protected String getFieldId(final FacesContext facesContext, final T component) {
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeCommandRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeCommandRenderer.java
deleted file mode 100644
index 0f9c17c..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeCommandRenderer.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.internal.renderkit.renderer;
-
-import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
-
-public class TreeCommandRenderer extends LinkRenderer {
-
-  @Override
-  protected TobagoClass getRendererCssClass() {
-    return TobagoClass.TREE_COMMAND;
-  }
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIconRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIconRenderer.java
index e27b8e7..5d06f96 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIconRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIconRenderer.java
@@ -32,11 +32,10 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class TreeIconRenderer extends RendererBase {
+public class TreeIconRenderer<T extends AbstractUITreeIcon> extends RendererBase<T> {
 
   /**
    * @deprecated since Tobago 3.0.0
@@ -55,17 +54,16 @@ public class TreeIconRenderer extends RendererBase {
   protected static final String LEAF = "image/treeNode-icon-leaf";
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUITreeIcon treeIcon = (AbstractUITreeIcon) component;
-    final AbstractUIData data = ComponentUtils.findAncestor(treeIcon, AbstractUIData.class);
-    final AbstractUITreeNode node = ComponentUtils.findAncestor(treeIcon, AbstractUITreeNode.class);
+    final AbstractUIData data = ComponentUtils.findAncestor(component, AbstractUIData.class);
+    final AbstractUITreeNode node = ComponentUtils.findAncestor(component, AbstractUITreeNode.class);
     final boolean folder = node.isFolder();
     final boolean expanded = folder && data.getExpandedState().isExpanded(node.getPath());
 
-    final String value = (String) treeIcon.getValue();
-    String closed = treeIcon.getClosed();
-    String open = treeIcon.getOpen();
+    final String value = (String) component.getValue();
+    String closed = component.getClosed();
+    String open = component.getOpen();
 
     if (closed == null) {
       closed = value;
@@ -89,10 +87,10 @@ public class TreeIconRenderer extends RendererBase {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.SPAN);
-    writer.writeIdAttribute(treeIcon.getClientId());
+    writer.writeIdAttribute(component.getClientId());
     writer.writeClassAttribute(
         TobagoClass.TREE_NODE__TOGGLE,
-        treeIcon.getCustomClass());
+        component.getCustomClass());
 
     if (source != null && source.startsWith("fa-")) {
       writer.startElement(HtmlElements.I);
@@ -104,7 +102,7 @@ public class TreeIconRenderer extends RendererBase {
       writer.endElement(HtmlElements.I);
     } else {
       writer.startElement(HtmlElements.IMG);
-      HtmlRendererUtils.writeDataAttributes(facesContext, writer, treeIcon);
+      HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
       writer.writeAttribute(HtmlAttributes.SRC, source, true);
       if (folder) {
         writer.writeAttribute(DataAttributes.OPEN, open, true);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIndentRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIndentRenderer.java
index 5e64307..75045ed 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIndentRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeIndentRenderer.java
@@ -36,14 +36,13 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class TreeIndentRenderer extends RendererBase {
+public class TreeIndentRenderer<T extends AbstractUITreeIndent> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUITreeIndent treeIndent = (AbstractUITreeIndent) component;
-    final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(treeIndent, AbstractUITreeNodeBase.class);
-    final AbstractUIData data = ComponentUtils.findAncestor(treeIndent, AbstractUIData.class);
+    final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(component, AbstractUITreeNodeBase.class);
+    final AbstractUIData data = ComponentUtils.findAncestor(component, AbstractUIData.class);
 
     if (node == null) {
       throw new NullPointerException(
@@ -54,18 +53,18 @@ public class TreeIndentRenderer extends RendererBase {
     }
 
     final boolean folder = node.isFolder();
-    final boolean showJunctions = treeIndent.isShowJunctions();
+    final boolean showJunctions = component.isShowJunctions();
     final boolean expanded = folder && data.getExpandedState().isExpanded(node.getPath());
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     writer.startElement(HtmlElements.SPAN);
-    writer.writeIdAttribute(treeIndent.getClientId(facesContext));
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, treeIndent);
+    writer.writeIdAttribute(component.getClientId(facesContext));
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeClassAttribute(
         TobagoClass.TREE_NODE__TOGGLE,
         !folder ? BootstrapClass.INVISIBLE : null,
-        treeIndent.getCustomClass());
+        component.getCustomClass());
 
     // encode tree junction
     if (!showJunctions) {
@@ -83,7 +82,7 @@ public class TreeIndentRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
     writer.endElement(HtmlElements.SPAN);
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeLabelRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeLabelRenderer.java
index 10f5bc4..ad33a17 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeLabelRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeLabelRenderer.java
@@ -31,21 +31,19 @@ import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
-import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class TreeLabelRenderer extends RendererBase {
+public class TreeLabelRenderer<T extends AbstractUITreeLabel> extends RendererBase<T> {
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final AbstractUIData data = ComponentUtils.findAncestor(component, AbstractUIData.class);
     final boolean listbox = data instanceof AbstractUITreeListbox;
 
-    final AbstractUITreeLabel label = (AbstractUITreeLabel) component;
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final String text = StringUtils.defaultString((String) label.getValue());
+    final String text = StringUtils.defaultString((String) component.getValue());
 
     if (listbox) {
       writer.writeText(text);
@@ -53,10 +51,10 @@ public class TreeLabelRenderer extends RendererBase {
       writer.startElement(HtmlElements.LABEL);
       writer.writeClassAttribute(
           TobagoClass.TREE_LABEL,
-          TobagoClass.TREE_LABEL.createMarkup(label.getMarkup()),
-          label.getCustomClass());
-      HtmlRendererUtils.writeDataAttributes(facesContext, writer, label);
-      final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, label);
+          TobagoClass.TREE_LABEL.createMarkup(component.getMarkup()),
+          component.getCustomClass());
+      HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+      final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
       if (title != null) {
         writer.writeAttribute(HtmlAttributes.TITLE, title, true);
       }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeListboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeListboxRenderer.java
index 964202f..bdad335 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeListboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeListboxRenderer.java
@@ -49,50 +49,48 @@ import java.util.List;
 
 import static org.apache.myfaces.tobago.util.ComponentUtils.SUB_SEPARATOR;
 
-public class TreeListboxRenderer extends RendererBase {
+public class TreeListboxRenderer<T extends AbstractUITreeListbox> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(TreeListboxRenderer.class);
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUITree tree = (AbstractUITree) component;
-    decodeState(facesContext, tree);
+  public void decodeInternal(final FacesContext facesContext, final T component) {
+    decodeState(facesContext, component);
   }
 
   @Override
-  public void encodeChildren(final FacesContext context, final UIComponent component) throws IOException {
+  public void encodeChildrenInternal(final FacesContext context, final T component) throws IOException {
     // will be rendered in encodeEnd()
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUITreeListbox tree = (AbstractUITreeListbox) component;
-    final String clientId = tree.getClientId(facesContext);
-    final Markup markup = tree.getMarkup();
+    final String clientId = component.getClientId(facesContext);
+    final Markup markup = component.getMarkup();
 
     writer.startElement(HtmlElements.TOBAGO_TREE_LISTBOX);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
         TobagoClass.TREE_LISTBOX,
         TobagoClass.TREE_LISTBOX.createMarkup(markup));
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, tree);
-    writer.writeAttribute(DataAttributes.SELECTION_MODE, tree.getSelectable().name(), false);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
+    writer.writeAttribute(DataAttributes.SELECTION_MODE, component.getSelectable().name(), false);
 
     writer.startElement(HtmlElements.INPUT);
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
     writer.writeNameAttribute(clientId + SUB_SEPARATOR + AbstractUIData.SUFFIX_SELECTED);
     writer.writeIdAttribute(clientId + SUB_SEPARATOR + AbstractUIData.SUFFIX_SELECTED);
-    writer.writeAttribute(HtmlAttributes.VALUE, encodeState(tree), false);
+    writer.writeAttribute(HtmlAttributes.VALUE, encodeState(component), false);
     writer.endElement(HtmlElements.INPUT);
 
     List<Integer> thisLevel = new ArrayList<>();
     thisLevel.add(0);
     List<Integer> nextLevel = new ArrayList<>();
-    Integer size = tree.getSize();
+    Integer size = component.getSize();
     size = Math.max(size != null ? size : 10, 2); // must be > 1, default is 10, if not set
-    int depth = tree.getTreeDataModel().getDepth();
+    int depth = component.getTreeDataModel().getDepth();
     if (depth < 0) {
       depth = 7; // XXX
       LOG.warn("No depth, set to {}!", depth);
@@ -119,7 +117,7 @@ public class TreeListboxRenderer extends RendererBase {
       }
 
       for (final Integer rowIndex : thisLevel) {
-        encodeSelectBox(facesContext, tree, writer, rowIndex, nextLevel, size);
+        encodeSelectBox(facesContext, component, writer, rowIndex, nextLevel, size);
       }
 
       thisLevel.clear();
@@ -132,7 +130,7 @@ public class TreeListboxRenderer extends RendererBase {
 
     writer.endElement(HtmlElements.TOBAGO_TREE_LISTBOX);
 
-    tree.setRowIndex(-1);
+    component.setRowIndex(-1);
   }
 
   private void encodeSelectBox(
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
index 54ee3a6..56ba361 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
@@ -24,7 +24,6 @@ import org.apache.myfaces.tobago.internal.component.AbstractUIData;
 import org.apache.myfaces.tobago.internal.component.AbstractUITree;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeListbox;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeNode;
-import org.apache.myfaces.tobago.internal.component.AbstractUITreeNodeBase;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeSelect;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.model.Selectable;
@@ -42,35 +41,32 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.component.UINamingContainer;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.Map;
 
-public class TreeNodeRenderer extends RendererBase {
+public class TreeNodeRenderer<T extends AbstractUITreeNode> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
+  public void decodeInternal(final FacesContext facesContext, final T component) {
 
-    final AbstractUITreeNode node = (AbstractUITreeNode) component;
+    super.decodeInternal(facesContext, component);
 
-    super.decode(facesContext, node);
-
-    if (ComponentUtils.isOutputOnly(node)) {
+    if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
-    final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
+    final AbstractUIData data = ComponentUtils.findAncestor(component, AbstractUIData.class);
     if (data instanceof AbstractUITreeListbox) {
       final String clientId = data.getClientId(facesContext);
-      final String nodeStateId = node.nodeStateId(facesContext);
+      final String nodeStateId = component.nodeStateId(facesContext);
       final Map<String, String> requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
-      final String nodeId = node.getClientId(facesContext);
-      final boolean folder = node.isFolder();
+      final String nodeId = component.getClientId(facesContext);
+      final boolean folder = component.isFolder();
 
       // expand state
       if (folder) {
@@ -91,8 +87,8 @@ public class TreeNodeRenderer extends RendererBase {
         selected = selected.replaceAll("\\[", ";");
         selected = selected.replaceAll("]", ";");
         selected = selected.replaceAll(",", ";");
-        final String searchString = ";" + node.getClientId(facesContext) + ";";
-        final AbstractUITreeSelect treeSelect = ComponentUtils.findDescendant(node, AbstractUITreeSelect.class);
+        final String searchString = ";" + component.getClientId(facesContext) + ";";
+        final AbstractUITreeSelect treeSelect = ComponentUtils.findDescendant(component, AbstractUITreeSelect.class);
         if (treeSelect != null) {
           treeSelect.setSubmittedValue(selected.contains(searchString));
         }
@@ -116,18 +112,16 @@ public class TreeNodeRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
-
-    final AbstractUITreeNodeBase node = (AbstractUITreeNodeBase) component;
-    final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
+    final AbstractUIData data = ComponentUtils.findAncestor(component, AbstractUIData.class);
     final boolean dataRendersRowContainer = data.isRendersRowContainer();
-    final String clientId = node.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final String parentId = data.getRowParentClientId();
     final boolean visible = data.isRowVisible();
-    final boolean folder = node.isFolder();
+    final boolean folder = component.isFolder();
     Markup markup = Markup.NULL;
-    final TreePath path = node.getPath();
+    final TreePath path = component.getPath();
     final SelectedState selectedState = data.getSelectedState();
     final boolean selected = data instanceof AbstractUITree && selectedState.isSelected(path);
 
@@ -164,11 +158,11 @@ public class TreeNodeRenderer extends RendererBase {
           null,
           TobagoClass.TREE_NODE.createMarkup(markup),
           hidden ? BootstrapClass.D_NONE : null,
-          node.getCustomClass());
+          component.getCustomClass());
       writer.writeAttribute(CustomAttributes.SELECTED, selected);
       writer.writeAttribute(CustomAttributes.EXPANDABLE, folder);
       writer.writeAttribute(CustomAttributes.INDEX, data.getRowIndex());
-      HtmlRendererUtils.writeDataAttributes(facesContext, writer, node);
+      HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
       if (parentId != null) {
         // TODO: replace with
         // todo writer.writeIdAttribute(parentId + SUB_SEPARATOR + AbstractUITree.SUFFIX_PARENT);
@@ -176,17 +170,16 @@ public class TreeNodeRenderer extends RendererBase {
         writer.writeAttribute(DataAttributes.TREE_PARENT, parentId, false);
         writer.writeAttribute(CustomAttributes.PARENT, parentId, false);
       }
-      writer.writeAttribute(DataAttributes.LEVEL, data.isShowRoot() ? node.getLevel() : node.getLevel() - 1);
+      writer.writeAttribute(DataAttributes.LEVEL, data.isShowRoot() ? component.getLevel() : component.getLevel() - 1);
     }
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUITreeNodeBase node = (AbstractUITreeNodeBase) component;
-    final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
-    final int level = node.getLevel();
-    final boolean folder = node.isFolder();
-    final boolean expanded = folder && data.getExpandedState().isExpanded(node.getPath()) || level == 0;
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
+    final AbstractUIData data = ComponentUtils.findAncestor(component, AbstractUIData.class);
+    final int level = component.getLevel();
+    final boolean folder = component.isFolder();
+    final boolean expanded = folder && data.getExpandedState().isExpanded(component.getPath()) || level == 0;
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeRenderer.java
index 81daec0..7bfb69c 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeRenderer.java
@@ -50,21 +50,20 @@ import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.List;
 
-public class TreeRenderer extends RendererBase {
+public class TreeRenderer<T extends AbstractUITree> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   protected static final String SCROLL_POSITION = "scrollPosition";
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUITree tree = (AbstractUITree) component;
+  public void decodeInternal(final FacesContext facesContext, final T component) {
     final String value = facesContext.getExternalContext().getRequestParameterMap().get(
-        tree.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + SCROLL_POSITION);
+        component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + SCROLL_POSITION);
     if (value != null) {
-      tree.getState().getScrollPosition().update(value);
+      component.getState().getScrollPosition().update(value);
     }
-    RenderUtils.decodedStateOfTreeData(facesContext, tree);
+    RenderUtils.decodedStateOfTreeData(facesContext, component);
   }
 
   @Override
@@ -73,9 +72,8 @@ public class TreeRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException {
-    final AbstractUITree tree = (AbstractUITree) component;
-    for (final UIComponent child : tree.getChildren()) {
+  public void encodeChildrenInternal(final FacesContext facesContext, final T component) throws IOException {
+    for (final UIComponent child : component.getChildren()) {
       if (child instanceof AbstractUIStyle) {
         child.encodeAll(facesContext);
       }
@@ -83,13 +81,12 @@ public class TreeRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
-    final AbstractUITree tree = (AbstractUITree) component;
-    final String clientId = tree.getClientId(facesContext);
-    final Markup markup = tree.getMarkup();
-    final UIComponent root = ComponentUtils.findDescendant(tree, AbstractUITreeNode.class);
+    final String clientId = component.getClientId(facesContext);
+    final Markup markup = component.getMarkup();
+    final UIComponent root = ComponentUtils.findDescendant(component, AbstractUITreeNode.class);
     if (root == null) {
       LOG.error("Can't find the tree root. This may occur while updating a tree from Tobago 1.0 to 1.5. "
           + "Please refer the documentation to see how to use tree tags.");
@@ -99,41 +96,41 @@ public class TreeRenderer extends RendererBase {
     writer.startElement(HtmlElements.TOBAGO_TREE);
     writer.writeIdAttribute(clientId);
     writer.writeClassAttribute(
-        tree.getCustomClass(),
+        component.getCustomClass(),
         TobagoClass.TREE.createMarkup(markup));
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, tree);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
     writer.writeAttribute(DataAttributes.SCROLL_PANEL, Boolean.TRUE.toString(), false);
 
-    final Selectable selectable = tree.getSelectable();
+    final Selectable selectable = component.getSelectable();
     if (selectable.isSupportedByTree()) {
       writer.writeAttribute(DataAttributes.SELECTABLE, selectable.name(), false);
       writer.writeAttribute(CustomAttributes.SELECTABLE, selectable.name(), false);
     }
 
-    final SelectedState selectedState = tree.getSelectedState();
+    final SelectedState selectedState = component.getSelectedState();
     final List<Integer> selectedValue = new ArrayList<>();
 
-    final ExpandedState expandedState = tree.getExpandedState();
+    final ExpandedState expandedState = component.getExpandedState();
     final List<Integer> expandedValue = new ArrayList<>();
 
-    final int last = tree.isRowsUnlimited() ? Integer.MAX_VALUE : tree.getFirst() + tree.getRows();
-    for (int rowIndex = tree.getFirst(); rowIndex < last; rowIndex++) {
-      tree.setRowIndex(rowIndex);
-      if (!tree.isRowAvailable()) {
+    final int last = component.isRowsUnlimited() ? Integer.MAX_VALUE : component.getFirst() + component.getRows();
+    for (int rowIndex = component.getFirst(); rowIndex < last; rowIndex++) {
+      component.setRowIndex(rowIndex);
+      if (!component.isRowAvailable()) {
         break;
       }
 
-      final TreePath path = tree.getPath();
+      final TreePath path = component.getPath();
 
       if (selectedState.isSelected(path)) {
         selectedValue.add(rowIndex);
       }
 
-      if (tree.isFolder() && expandedState.isExpanded(path)) {
+      if (component.isFolder() && expandedState.isExpanded(path)) {
         expandedValue.add(rowIndex);
       }
 
-      for (final UIComponent child : tree.getChildren()) {
+      for (final UIComponent child : component.getChildren()) {
         if (child instanceof AbstractUIStyle) {
           // ignore, this is rendered in encodeChildren()
         } else {
@@ -141,7 +138,7 @@ public class TreeRenderer extends RendererBase {
         }
       }
     }
-    tree.setRowIndex(-1);
+    component.setRowIndex(-1);
 
     writer.startElement(HtmlElements.INPUT);
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
@@ -165,7 +162,7 @@ public class TreeRenderer extends RendererBase {
     writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + SCROLL_POSITION);
     writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + SCROLL_POSITION);
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
-    writer.writeAttribute(HtmlAttributes.VALUE, tree.getState().getScrollPosition().encode(), false);
+    writer.writeAttribute(HtmlAttributes.VALUE, component.getState().getScrollPosition().encode(), false);
     writer.writeAttribute(DataAttributes.SCROLL_POSITION, Boolean.TRUE.toString(), false);
     writer.endElement(HtmlElements.INPUT);
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeSelectRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeSelectRenderer.java
index 32474f7..2d5411c 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeSelectRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeSelectRenderer.java
@@ -42,28 +42,26 @@ import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.faces.component.UIComponent;
 import javax.faces.component.UINamingContainer;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.Map;
 
-public class TreeSelectRenderer extends RendererBase {
+public class TreeSelectRenderer<T extends AbstractUITreeSelect> extends RendererBase<T> {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
-  public void decode(final FacesContext facesContext, final UIComponent component) {
-    final AbstractUITreeSelect select = (AbstractUITreeSelect) component;
-    final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(select, AbstractUITreeNodeBase.class);
+  public void decodeInternal(final FacesContext facesContext, final T component) {
+    final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(component, AbstractUITreeNodeBase.class);
     final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
 
-    if (ComponentUtils.isOutputOnly(select)) {
+    if (ComponentUtils.isOutputOnly(component)) {
       return;
     }
 
-    final String clientId = select.getClientId(facesContext);
+    final String clientId = component.getClientId(facesContext);
     final String name;
     if (data.getSelectable().isSingle()) {
       name = getClientIdWithoutRowIndex(data, clientId);
@@ -78,30 +76,29 @@ public class TreeSelectRenderer extends RendererBase {
     }
 
     final boolean selected = clientId.equals(parameter);
-    if (!select.isValueStoredInState()) {
-      select.setSubmittedValue(selected ? "true" : "false");
+    if (!component.isValueStoredInState()) {
+      component.setSubmittedValue(selected ? "true" : "false");
     }
   }
 
   @Override
-  public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
-    final AbstractUITreeSelect treeSelect = (AbstractUITreeSelect) component;
-    final AbstractUITree tree = ComponentUtils.findAncestor(treeSelect, AbstractUITree.class);
-    final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(treeSelect, AbstractUITreeNodeBase.class);
+    final AbstractUITree tree = ComponentUtils.findAncestor(component, AbstractUITree.class);
+    final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(component, AbstractUITreeNodeBase.class);
     final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
     if (data instanceof AbstractUITreeListbox) {
-      writer.write(StringUtils.defaultString(treeSelect.getLabel()));
+      writer.write(StringUtils.defaultString(component.getLabel()));
       return;
     }
 
-    final String id = treeSelect.getClientId(facesContext);
-    final String currentValue = getCurrentValue(facesContext, treeSelect);
+    final String id = component.getClientId(facesContext);
+    final String currentValue = getCurrentValue(facesContext, component);
     final boolean checked;
-    if (treeSelect.isValueStoredInState()) {
+    if (component.isValueStoredInState()) {
       checked = data.getSelectedState().isSelected(node.getPath());
     } else {
       checked = "true".equals(currentValue);
@@ -109,19 +106,19 @@ public class TreeSelectRenderer extends RendererBase {
 
     final boolean folder = data.isFolder();
     final Selectable selectable = data.getSelectable();
-    final boolean showCustomControl = treeSelect.isShowCheckbox()
+    final boolean showCustomControl = component.isShowCheckbox()
         && selectable != Selectable.none && (!selectable.isLeafOnly() || !folder);
 
     writer.startElement(HtmlElements.TOBAGO_TREE_SELECT);
-    final Markup markup = treeSelect.getMarkup();
+    final Markup markup = component.getMarkup();
     writer.writeClassAttribute(
-        treeSelect.getCustomClass(),
+        component.getCustomClass(),
         TobagoClass.TREE_SELECT.createMarkup(markup),
         // TODO: check rendered page for other selectables. Are them looking good?
         showCustomControl ? BootstrapClass.FORM_CHECK_INLINE : null,
         showCustomControl && selectable.isMulti() ? BootstrapClass.FORM_CHECK : null,
         showCustomControl && selectable.isSingle() ? BootstrapClass.FORM_CHECK : null);
-    HtmlRendererUtils.writeDataAttributes(facesContext, writer, treeSelect);
+    HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     if (showCustomControl) {
       writer.startElement(HtmlElements.INPUT);
@@ -141,11 +138,11 @@ public class TreeSelectRenderer extends RendererBase {
       writer.endElement(HtmlElements.INPUT);
     }
 
-    final String label = treeSelect.getLabel();
+    final String label = component.getLabel();
     writer.startElement(HtmlElements.LABEL);
     writer.writeClassAttribute(TobagoClass.TREE_SELECT__LABEL,
         showCustomControl ? BootstrapClass.FORM_CHECK_LABEL : null);
-    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, treeSelect);
+    final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     if (title != null) {
       writer.writeAttribute(HtmlAttributes.TITLE, title, true);
     }
@@ -154,7 +151,7 @@ public class TreeSelectRenderer extends RendererBase {
     writer.endElement(HtmlElements.LABEL);
 
     if (showCustomControl) {
-      final CommandMap behaviorCommands = getBehaviorCommands(facesContext, treeSelect);
+      final CommandMap behaviorCommands = getBehaviorCommands(facesContext, component);
       if (behaviorCommands != null) {
         Map<ClientBehaviors, Command> other = behaviorCommands.getOther();
         if (other != null) {
@@ -175,6 +172,6 @@ public class TreeSelectRenderer extends RendererBase {
   }
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
   }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/VerbatimRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/VerbatimRenderer.java
index 0273805..7713236 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/VerbatimRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/VerbatimRenderer.java
@@ -29,10 +29,10 @@ import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 
-public class VerbatimRenderer extends RendererBase {
+public class VerbatimRenderer<T extends UIComponent> extends RendererBase<T> {
 
   @Override
-  public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException {
+  public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnNodeTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnNodeTagDeclaration.java
index f5b3174..c59acc0 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnNodeTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnNodeTagDeclaration.java
@@ -39,7 +39,7 @@ import javax.faces.component.UIColumn;
  */
 @SuppressWarnings("ALL")
 @Tag(name = "columnNode")
-@BodyContentDescription(anyTagOf = "<tc:treeIndent>|<tc:treeIcon>|<tc:treeSelect>|<tc:treeLabel>|<tc:treeCommand>")
+@BodyContentDescription(anyTagOf = "<tc:treeIndent>|<tc:treeIcon>|<tc:treeSelect>|<tc:treeLabel>|<tc:link>")
 @UIComponentTag(
     uiComponent = "org.apache.myfaces.tobago.component.UIColumnNode",
     uiComponentFacesClass = "javax.faces.component.UIColumn",
@@ -54,7 +54,7 @@ import javax.faces.component.UIColumn;
         "org.apache.myfaces.tobago.TreeIcon",
         "org.apache.myfaces.tobago.TreeSelect",
         "org.apache.myfaces.tobago.TreeLabel",
-        "org.apache.myfaces.tobago.TreeCommand"
+        "org.apache.myfaces.tobago.Link"
     })
 public interface ColumnNodeTagDeclaration
     extends HasIdBindingAndRendered, HasTip, IsDisabled, IsVisual, HasLabel {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeCommandTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeCommandTagDeclaration.java
deleted file mode 100644
index 18e6478..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeCommandTagDeclaration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.internal.taglib.component;
-
-import org.apache.myfaces.tobago.apt.annotation.Behavior;
-import org.apache.myfaces.tobago.apt.annotation.BodyContentDescription;
-import org.apache.myfaces.tobago.apt.annotation.Facet;
-import org.apache.myfaces.tobago.apt.annotation.Tag;
-import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
-import org.apache.myfaces.tobago.component.ClientBehaviors;
-import org.apache.myfaces.tobago.component.Facets;
-import org.apache.myfaces.tobago.component.RendererTypes;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasAccessKey;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasAction;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasActionListener;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasConfirmation;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasFragment;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasIdBindingAndRendered;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasLabel;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasLink;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasOutcome;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasTabIndex;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasTarget;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasTip;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsDisabledBySecurity;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsImmediateCommand;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsOmit;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsTransition;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsVisual;
-
-import javax.faces.component.UICommand;
-
-/**
- * Renders a command inside of a tree.
- *
- * @deprecated since 4.0.0, please use tc:link
- */
-@Deprecated
-@Tag(name = "treeCommand")
-@BodyContentDescription(anyTagOf = "facestag")
-@UIComponentTag(
-    uiComponent = "org.apache.myfaces.tobago.component.UITreeCommand",
-    uiComponentFacesClass = "javax.faces.component.UICommand",
-    interfaces = {
-        "org.apache.myfaces.tobago.component.SupportsAccessKey"
-    },
-    componentFamily = UICommand.COMPONENT_FAMILY,
-    allowedChildComponenents = "NONE",
-    facets = {
-        @Facet(
-            name = Facets.CONFIRMATION,
-            description = "Contains a UIOutput instance with the confirmation message.",
-            allowedChildComponenents = "org.apache.myfaces.tobago.Out")},
-    behaviors = {
-        @Behavior(
-            name = ClientBehaviors.CLICK,
-            description = "Behavior of a click event.",
-            isDefault = true),
-        @Behavior(
-            name = ClientBehaviors.DBLCLICK)
-    },
-    rendererType = RendererTypes.TREE_COMMAND)
-public interface TreeCommandTagDeclaration
-    extends HasIdBindingAndRendered, HasAction, HasActionListener, IsImmediateCommand, HasConfirmation,
-    HasLink, HasOutcome, HasFragment, IsTransition, HasTarget, IsDisabledBySecurity,
-    IsOmit, HasLabel, HasAccessKey, HasTip, HasTabIndex, IsVisual {
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeNodeTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeNodeTagDeclaration.java
index 94cf07f..27545ec 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeNodeTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeNodeTagDeclaration.java
@@ -38,7 +38,7 @@ import javax.faces.component.UIColumn;
  */
 @SuppressWarnings("ALL")
 @Tag(name = "treeNode")
-@BodyContentDescription(anyTagOf = "<tc:treeIndent>|<tc:treeIcon>|<tc:treeSelect>|<tc:treeLabel>|<tc:treeCommand>")
+@BodyContentDescription(anyTagOf = "<tc:treeIndent>|<tc:treeIcon>|<tc:treeSelect>|<tc:treeLabel>|<tc:link>")
 @UIComponentTag(
     uiComponent = "org.apache.myfaces.tobago.component.UITreeNode",
     uiComponentFacesClass = "javax.faces.component.UIColumn",
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
index ccf4d3e..6e2f4b5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
@@ -56,11 +56,72 @@ import java.lang.invoke.MethodHandles;
 import java.util.List;
 import java.util.Map;
 
-public class RendererBase extends Renderer {
+public abstract class RendererBase<T extends UIComponent> extends Renderer {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-  protected String getCurrentValue(final FacesContext facesContext, final UIComponent component) {
+  // begin of "redefine" the method signatur (generics): UIComponent -> T
+
+  @Override
+  public final void encodeBegin(FacesContext context, UIComponent component) throws IOException {
+    this.encodeBeginInternal(context, (T) component);
+  }
+
+  public void encodeBeginInternal(FacesContext context, T component) throws IOException {
+    super.encodeBegin(context, component);
+  }
+
+  @Override
+  public final void encodeChildren(FacesContext context, UIComponent component) throws IOException {
+    this.encodeChildrenInternal(context, (T) component);
+  }
+
+  public void encodeChildrenInternal(FacesContext context, T component) throws IOException {
+    super.encodeChildren(context, component);
+  }
+
+  @Override
+  public final void encodeEnd(FacesContext context, UIComponent component) throws IOException {
+    this.encodeEndInternal(context, (T) component);
+  }
+
+  public void encodeEndInternal(FacesContext context, T component) throws IOException {
+    super.encodeEnd(context, component);
+  }
+
+  @Override
+  public final void decode(FacesContext context, UIComponent component) {
+    this.decodeInternal(context, (T) component);
+  }
+
+  public void decodeInternal(FacesContext context, T component) {
+    super.decode(context, component);
+  }
+
+  @Override
+  public Object getConvertedValue(final FacesContext facesContext, final UIComponent component, final Object submittedValue)
+      throws ConverterException {
+    return getConvertedValueInternal(facesContext, (T)component, submittedValue);
+  }
+
+  public Object getConvertedValueInternal(
+      final FacesContext context, final T component, final Object submittedValue)
+      throws ConverterException {
+    if (!(submittedValue instanceof String)) {
+      return submittedValue;
+    }
+    final Converter converter = ComponentUtils.getConverter(context, component, submittedValue);
+    if (converter != null) {
+      return converter.getAsObject(context, component, (String) submittedValue);
+    } else {
+      return submittedValue;
+    }
+  }
+
+
+// end of "redefine"
+
+  protected String getCurrentValue(final FacesContext facesContext, final T component) {
 
     if (component instanceof ValueHolder) {
       final ValueHolder valueHolder = (ValueHolder) component;
@@ -82,24 +143,6 @@ public class RendererBase extends Renderer {
     }
   }
 
-  @Override
-  public Object getConvertedValue(final FacesContext context, final UIComponent component, final Object submittedValue)
-      throws ConverterException {
-    if (!(submittedValue instanceof String)) {
-      return submittedValue;
-    }
-    final Converter converter = ComponentUtils.getConverter(context, component, submittedValue);
-    if (converter != null) {
-      return converter.getAsObject(context, component, (String) submittedValue);
-    } else {
-      return submittedValue;
-    }
-  }
-
-  public void onComponentCreated(
-      final FacesContext facesContext, final UIComponent component, final UIComponent parent) {
-  }
-
   protected TobagoResponseWriter getResponseWriter(final FacesContext facesContext) {
     final ResponseWriter writer = facesContext.getResponseWriter();
     if (writer instanceof TobagoResponseWriter) {
@@ -110,7 +153,7 @@ public class RendererBase extends Renderer {
   }
 
   /**
-   * Special implementation for the reload facet (e.g. for tc:panel and tc:sheet.
+   * Special implementation for the reload facet (e.g. for tc:panel and tc:sheet).
    */
   public void encodeReload(FacesContext facesContext, AbstractUIReload reload) throws IOException {
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
@@ -178,8 +221,8 @@ public class RendererBase extends Renderer {
     writer.endElement(HtmlElements.TOBAGO_BEHAVIOR);
   }
 
-  protected CommandMap getBehaviorCommands(final FacesContext facesContext,
-                                               final ClientBehaviorHolder clientBehaviorHolder) {
+  protected CommandMap getBehaviorCommands(
+      final FacesContext facesContext, final ClientBehaviorHolder clientBehaviorHolder) {
     CommandMap commandMap = null;
 
     for (final Map.Entry<String, List<ClientBehavior>> entry : clientBehaviorHolder.getClientBehaviors().entrySet()) {
@@ -219,15 +262,16 @@ public class RendererBase extends Renderer {
     return commandMap;
   }
 
-  private static ClientBehaviorContext getClientBehaviorContext(final FacesContext facesContext,
-      final ClientBehaviorHolder clientBehaviorHolder, final String eventName) {
-    UIComponent component = (UIComponent) clientBehaviorHolder;
+  private static ClientBehaviorContext getClientBehaviorContext(
+      final FacesContext facesContext, final ClientBehaviorHolder clientBehaviorHolder, final String eventName) {
+    final UIComponent component = (UIComponent) clientBehaviorHolder;
     return ClientBehaviorContext.createClientBehaviorContext(facesContext, component, eventName,
         component.getClientId(facesContext), null);
   }
 
-  private static CommandMap getCommandMap(final FacesContext facesContext,
-      final ClientBehaviorContext clientBehaviorContext, final ClientBehavior clientBehavior) {
+  private static CommandMap getCommandMap(
+      final FacesContext facesContext, final ClientBehaviorContext clientBehaviorContext,
+      final ClientBehavior clientBehavior) {
     if (clientBehavior instanceof ClientBehaviorBase) {
       String type = ((ClientBehaviorBase) clientBehavior).getRendererType();
 
@@ -246,7 +290,7 @@ public class RendererBase extends Renderer {
     return null;
   }
 
-  protected void decodeClientBehaviors(final FacesContext facesContext, final UIComponent component) {
+  protected void decodeClientBehaviors(final FacesContext facesContext, final T component) {
     if (component instanceof ClientBehaviorHolder) {
       final ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) component;
       final Map<String, List<ClientBehavior>> clientBehaviors = clientBehaviorHolder.getClientBehaviors();
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
index e488521..d4a529e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
@@ -229,7 +229,6 @@ public enum TobagoClass implements CssItem {
   TREE("tobago-tree"),
   TREE__EXPANDED("tobago-tree-expanded"),
   TREE__SELECTED("tobago-tree-selected"),
-  TREE_COMMAND("tobago-treeCommand"),
   TREE_LABEL("tobago-treeLabel"),
   TREE_LISTBOX("tobago-treeListbox"),
   TREE_LISTBOX__LEVEL("tobago-treeListbox-level"),
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java
index 1dd52de..def5450 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java
@@ -66,7 +66,6 @@ import org.apache.myfaces.tobago.component.UITab;
 import org.apache.myfaces.tobago.component.UITabGroup;
 import org.apache.myfaces.tobago.component.UITextarea;
 import org.apache.myfaces.tobago.component.UITree;
-import org.apache.myfaces.tobago.component.UITreeCommand;
 import org.apache.myfaces.tobago.component.UITreeIcon;
 import org.apache.myfaces.tobago.component.UITreeIndent;
 import org.apache.myfaces.tobago.component.UITreeLabel;
@@ -150,7 +149,6 @@ public class EventController implements Serializable {
     eventsOnComponents.add(new EventsOnComponent(new UITabGroup()));
     eventsOnComponents.add(new EventsOnComponent(new UITextarea()));
     eventsOnComponents.add(new EventsOnComponent(new UITree()));
-    eventsOnComponents.add(new EventsOnComponent(new UITreeCommand()));
     eventsOnComponents.add(new EventsOnComponent(new UITreeIcon()));
     eventsOnComponents.add(new EventsOnComponent(new UITreeIndent()));
     eventsOnComponents.add(new EventsOnComponent(new UITreeLabel()));
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/30-whats-new/60-new-in-5-0/Tobago_5.0.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/30-whats-new/60-new-in-5-0/Tobago_5.0.xhtml
index 47e93f3..bd2c1b0 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/30-whats-new/60-new-in-5-0/Tobago_5.0.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/30-whats-new/60-new-in-5-0/Tobago_5.0.xhtml
@@ -35,6 +35,7 @@
       <li>Refactoring: JavaScript -> TypeScript</li>
       <li>Refactoring: ResourceBunde and MessageBundle</li>
       <li>Update to Bootstrap 5</li>
+      <li>Remove &lt;tc:treeCommand&gt;, just use &lt;tc:link&gt;</li>
       <li>...</li>
       <li>Bugfixes</li>
     </ul>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/00-command/Tree_Command_Types.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/00-command/Tree_Command_Types.xhtml
index f7d8477..d27e1e6 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/00-command/Tree_Command_Types.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/00-command/Tree_Command_Types.xhtml
@@ -22,7 +22,7 @@
                 xmlns:tc="http://myfaces.apache.org/tobago/component"
                 xmlns:ui="http://java.sun.com/jsf/facelets">
 
-  <p>The <code class="language-markup">&lt;tc:treeCommand/></code> tag can be added to a
+  <p>The <code class="language-markup">&lt;tc:link/></code> tag can be added to a
     <code class="language-markup">&lt;tc:treeNode/></code> tag.
     The command can be used to execute an action or a link.</p>
   <p><tc:link label="Tag Library Documentation" image="#{request.contextPath}/image/feather-leaf.png"
@@ -39,9 +39,9 @@
       <tc:treeNode id="treeNode">
         <tc:treeIndent showJunctions="false"/>
         <tc:treeLabel value="#{node.name}" rendered="#{node.childCount > 0}"/>
-        <tc:treeCommand id="actionCommand" label="#{node.name}" rendered="#{node.childCount == 0 and empty node.url}"
+        <tc:link id="actionCommand" label="#{node.name}" rendered="#{node.childCount == 0 and empty node.url}"
                         action="#{treeCommandTypesController.increaseActionCount(node.action)}"/>
-        <tc:treeCommand label="#{node.name}" rendered="#{node.childCount == 0 and not empty node.url}"
+        <tc:link label="#{node.name}" rendered="#{node.childCount == 0 and not empty node.url}"
                         link="#{node.url}"/>
       </tc:treeNode>
     </tc:tree>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/03-menu/Tree_Menu.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/03-menu/Tree_Menu.xhtml
index 54f9e9c..d451b53 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/03-menu/Tree_Menu.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/03-menu/Tree_Menu.xhtml
@@ -28,7 +28,7 @@
   </p>
   <p>
     The menu nodes can be build inside of <code class="language-markup">&lt;tc:treeNode/></code> with
-    <code class="language-markup">&lt;tc:treeCommand/></code>,
+    <code class="language-markup">&lt;tc:link/></code>,
     <code class="language-markup">&lt;tc:treeLabel/></code>,
     <code class="language-markup">&lt;tc:treeIcon/></code> and
     <code class="language-markup">&lt;tc:treeIndent/></code> tags.
@@ -40,7 +40,7 @@
     <pre><code class="language-markup">&lt;tc:tree value="\#{treeController.sample}" ...></code></pre>
     <tc:tree value="#{treeController.sample}" var="node">
       <tc:treeNode>
-        <tc:treeCommand label="#{node.userObject.name}"/>
+        <tc:link label="#{node.userObject.name}"/>
         <tc:treeIndent showJunctions="true">
           <tc:style customClass="float-right"/>
         </tc:treeIndent>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/9010-mode-valueIfSet/Mode_ValueIfSet.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/9010-mode-valueIfSet/Mode_ValueIfSet.xhtml
index 12536e6..fc45217 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/9010-mode-valueIfSet/Mode_ValueIfSet.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/9010-mode-valueIfSet/Mode_ValueIfSet.xhtml
@@ -16,90 +16,17 @@
  * limitations under the License.
 -->
 
-<ui:composition template="/main.xhtml"
+<ui:composition template="/plain.xhtml"
                 xmlns="http://www.w3.org/1999/xhtml"
                 xmlns:c="http://java.sun.com/jsp/jstl/core"
                 xmlns:tc="http://myfaces.apache.org/tobago/component"
                 xmlns:ui="http://java.sun.com/jsf/facelets">
 
-  <tc:section label="Test of the &lt;tc:attribute mode='valueIfSet'>">
+  <tc:segmentLayout medium="6seg 6seg">
 
-    <tc:box label="Set value via &lt;tc:attribute>">
+    <tc:in id="direct1" label="label 1" labelLayout="segmentRight"/>
+    <tc:in id="direct2" label="label 2" labelLayout="segmentLeft"/>
 
-      <tc:segmentLayout medium="4seg 4seg 4seg">
-
-        <tc:label value="label:"/>
-        <tc:label value="test field:"/>
-        <tc:label value="expected value:"/>
-
-        <tc:label value="direct literal:"/>
-        <tc:in id="direct" label="literal value" labelLayout="segmentRight">
-          <tc:attribute name="value" value="literal value" mode="valueIfSet"/>
-        </tc:in>
-
-        <c:set var="value1" value="c:set variable"/>
-        <tc:label value="via c:set:"/>
-        <tc:in id="v1" label="c:set variable" labelLayout="segmentRight">
-          <tc:attribute name="value" value="#{value1}" mode="valueIfSet"/>
-        </tc:in>
-
-        <c:set var="value2" value="#{value1}"/>
-        <tc:label value="via c:set in c:set:"/>
-        <tc:in id="v2" label="c:set variable" labelLayout="segmentRight">
-          <tc:attribute name="value" value="#{value2}" mode="valueIfSet"/>
-        </tc:in>
-
-        <c:set var="value3" value="#{value1} with other text"/>
-        <tc:label value="via c:set in c:set with other text:"/>
-        <tc:in id="v3" label="c:set variable with other text" labelLayout="segmentRight">
-          <tc:attribute name="value" value="#{value3}" mode="valueIfSet"/>
-        </tc:in>
-
-        <c:set var="value4" value="#{attributeController.value}"/>
-        <tc:label value="java session variable"/>
-        <tc:in id="v4" label="value from model" labelLayout="segmentRight">
-          <tc:attribute name="value" value="#{value4}" mode="valueIfSet"/>
-        </tc:in>
-
-        <tc:label value="undefined variable (empty)"/>
-        <tc:in id="vu" label="" labelLayout="segmentRight">
-          <tc:attribute name="value" value="#{value_undefined}" mode="valueIfSet"/>
-        </tc:in>
-      </tc:segmentLayout>
-    </tc:box>
-
-    <tc:box label="Set id via &lt;tc:attribute>" id="id-box">
-
-      <tc:segmentLayout medium="4seg 4seg 4seg">
-
-        <tc:label value="label:"/>
-        <tc:label value="test field:"/>
-        <tc:label value="expected id:"/>
-
-        <tc:label value="id"/>
-        <tc:in label="page:mainForm:my_number_1::field" labelLayout="segmentRight">
-          <tc:attribute name="id" value="my_number_1" mode="valueIfSet"/>
-        </tc:in>
-
-        <tc:label value="id (not implemented)"/>
-        <tc:in label="'autogenerated'" labelLayout="segmentRight">
-          <tc:attribute name="id" value="#{'my_number_2'}" mode="valueIfSet"/>
-        </tc:in>
-
-        <c:set var="id3" value="my_number_3"/>
-        <tc:label value="id"/>
-        <tc:in label="page:mainForm:my_number_3::field" labelLayout="segmentRight">
-          <tc:attribute name="id" value="#{id3}" mode="valueIfSet"/>
-        </tc:in>
-
-        <tc:label value="id (undefined)"/>
-        <tc:in label="'autogenerated'" labelLayout="segmentRight">
-          <tc:attribute name="id" value="#{id_undefined}" mode="valueIfSet"/>
-        </tc:in>
-
-      </tc:segmentLayout>
-    </tc:box>
-
-  </tc:section>
+  </tc:segmentLayout>
 
 </ui:composition>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/navigation.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/navigation.xhtml
index c8781e9..1304fcf 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/navigation.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/navigation.xhtml
@@ -22,7 +22,7 @@
            xmlns:tc="http://myfaces.apache.org/tobago/component">
   <tc:tree id="nav" value="#{navigationTree.tree}" var="node" state="#{navigationState.state}">
     <tc:treeNode id="node">
-      <tc:treeCommand
+      <tc:link
               id="cmd"
               label="» #{node.label}"
               outcome="#{node.outcome}"/>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js b/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js
index b22460e..7878e05 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js
@@ -57,8 +57,7 @@ QUnit.test("wait for test", function (assert) {
   let waitingDone = false;
   let interval = setInterval(function () {
     contentWindowName = document.getElementById("page:testframe").contentWindow.name;
-    waitingDone = (contentWindowName !== "page:testframe" && contentWindowName !== "ds-tempWindowId")
-        || new RegExp('[\?&]base=([^&#]*)').exec(window.location.href)[1].indexOf("error%2F") === 0;
+    waitingDone = new RegExp('[\?&]base=([^&#]*)').exec(window.location.href)[1].indexOf("error%2F") === 0;
     if (new Date().getTime() - startTime >= 20000 || waitingDone) {
       clearInterval(interval);
       assert.ok(waitingDone);
@@ -92,11 +91,7 @@ QUnit.test("test '???'", function (assert) {
 
 beforeEach(function (done) {
   const test = new JasmineTestTool(done);
-  test.wait(() => document.getElementById("page:testframe")
-      && document.getElementById("page:testframe").contentWindow
-      && document.getElementById("page:testframe").contentWindow.name
-      && document.getElementById("page:testframe").contentWindow.name !== "page:testframe"
-      && document.getElementById("page:testframe").contentWindow.name !== "ds-tempWindowId");
+  test.wait(() => document.getElementById("page:testframe"));
   test.do(() => expect("waiting for testframe is done").toBe("waiting for testframe is done"));
   test.start();
 });
diff --git a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css
index 27a1a6b..62537d5 100644
--- a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css
+++ b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css
@@ -10511,7 +10511,7 @@ h1 button.tobago-link, .h1 button.tobago-link, h2 button.tobago-link, .h2 button
   font-weight: inherit;
 }
 
-button.tobago-link, button.tobago-treeCommand {
+button.tobago-link {
   color: #0d6efd;
   border-width: 0;
   padding: 0;
@@ -10519,23 +10519,23 @@ button.tobago-link, button.tobago-treeCommand {
   text-align: left;
 }
 
-button.tobago-link:focus, button.tobago-link:hover, button.tobago-treeCommand:focus, button.tobago-treeCommand:hover {
+button.tobago-link:focus, button.tobago-link:hover {
   color: #58512e;
   cursor: pointer;
   outline: none;
   text-decoration: underline;
 }
 
-button.tobago-link:disabled, button.tobago-treeCommand:disabled {
+button.tobago-link:disabled {
   color: #777777;
 }
 
-button.tobago-link:disabled:hover, button.tobago-treeCommand:disabled:hover {
+button.tobago-link:disabled:hover {
   cursor: not-allowed;
   text-decoration: none;
 }
 
-button.tobago-link:disabled > img, button.tobago-treeCommand:disabled > img {
+button.tobago-link:disabled > img {
   opacity: .65;
 }
 
@@ -10616,10 +10616,6 @@ a.tobago-messages-button, a.tobago-help-button, a.tobago-popover-button {
   margin-bottom: 0;
 }
 
-.tobago-flexLayout.tobago-messages-container > {
-  /* TODO: maybe add here some stuff for vaadin-combo-box-light for tc:tobago-suggest */
-}
-
 .tobago-flexLayout.tobago-messages-container > .tobago-input-group-outer, .tobago-flexLayout.tobago-messages-container > .tobago-selectManyShuttle {
   flex: 1 0 0px;
 }
@@ -11651,10 +11647,6 @@ tobago-tab-group {
   margin-right: 0.375rem;
 }
 
-.tobago-treeCommand {
-  cursor: pointer;
-}
-
 .tobago-treeNode[data-tobago-level] {
   margin-left: 7rem;
 }
diff --git a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css.map b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css.map
index 459b7da..4fd71e3 100644
--- a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../scss/_custom.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/m [...]
\ No newline at end of file
+{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../scss/_custom.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/m [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css
index 6e92c1c..c6db3cf 100644
--- a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#ff00be;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#ffffff;--bs-gray:#777777;--bs-gray-dark:#323232;--bs-primary:#529696;--bs-secondary:#b2a76d;--bs-success:#abf5ff;--bs-info:#389c30;--bs-warning:#ff00be;--bs-danger:#ff00be;--bs-light:#ffffff;--bs-dark:#529696;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Robo [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#ff00be;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#ffffff;--bs-gray:#777777;--bs-gray-dark:#323232;--bs-primary:#529696;--bs-secondary:#b2a76d;--bs-success:#abf5ff;--bs-info:#389c30;--bs-warning:#ff00be;--bs-danger:#ff00be;--bs-light:#ffffff;--bs-dark:#529696;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Robo [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css.map b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css.map
index 53b2c11..9173381 100644
--- a/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-charlotteville/npm/dist/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_mod [...]
\ No newline at end of file
+{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_mod [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css
index c77d58b..1659be5 100644
--- a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css
+++ b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css
@@ -10537,7 +10537,7 @@ h1 button.tobago-link, .h1 button.tobago-link, h2 button.tobago-link, .h2 button
   font-weight: inherit;
 }
 
-button.tobago-link, button.tobago-treeCommand {
+button.tobago-link {
   color: #130E8F;
   border-width: 0;
   padding: 0;
@@ -10545,23 +10545,23 @@ button.tobago-link, button.tobago-treeCommand {
   text-align: left;
 }
 
-button.tobago-link:focus, button.tobago-link:hover, button.tobago-treeCommand:focus, button.tobago-treeCommand:hover {
+button.tobago-link:focus, button.tobago-link:hover {
   color: #dbb2ff;
   cursor: pointer;
   outline: none;
   text-decoration: underline;
 }
 
-button.tobago-link:disabled, button.tobago-treeCommand:disabled {
+button.tobago-link:disabled {
   color: #777777;
 }
 
-button.tobago-link:disabled:hover, button.tobago-treeCommand:disabled:hover {
+button.tobago-link:disabled:hover {
   cursor: not-allowed;
   text-decoration: none;
 }
 
-button.tobago-link:disabled > img, button.tobago-treeCommand:disabled > img {
+button.tobago-link:disabled > img {
   opacity: .65;
 }
 
@@ -10642,10 +10642,6 @@ a.tobago-messages-button, a.tobago-help-button, a.tobago-popover-button {
   margin-bottom: 0;
 }
 
-.tobago-flexLayout.tobago-messages-container > {
-  /* TODO: maybe add here some stuff for vaadin-combo-box-light for tc:tobago-suggest */
-}
-
 .tobago-flexLayout.tobago-messages-container > .tobago-input-group-outer, .tobago-flexLayout.tobago-messages-container > .tobago-selectManyShuttle {
   flex: 1 0 0px;
 }
@@ -11677,10 +11673,6 @@ tobago-tab-group {
   margin-right: 0.375rem;
 }
 
-.tobago-treeCommand {
-  cursor: pointer;
-}
-
 .tobago-treeNode[data-tobago-level] {
   margin-left: 7rem;
 }
diff --git a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css.map b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css.map
index 7aa79f9..33d1ac8 100644
--- a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../scss/_custom.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/m [...]
\ No newline at end of file
+{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../scss/_custom.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/m [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css
index e8baefe..6e92327 100644
--- a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";@font-face{font-family:Amaranth;font-style:normal;font-weight:400;src:url(../fonts/Amaranth-Regular.otf) format("opentype")}@font-face{font-family:Amaranth;font-style:normal;font-weight:700;src:url(../fonts/Amaranth-Bold.otf) format("opentype")}@font-face{font-family:Amaranth;font-style:italic;src:url(../fonts/Amaranth-Italic.otf) format("opentype")}@font-face{font-family:Amaranth;font-style:italic;font-weight:700;src:url(../fonts/Amaranth-BoldItalic.otf) format("opentyp [...]
+@charset "UTF-8";@font-face{font-family:Amaranth;font-style:normal;font-weight:400;src:url(../fonts/Amaranth-Regular.otf) format("opentype")}@font-face{font-family:Amaranth;font-style:normal;font-weight:700;src:url(../fonts/Amaranth-Bold.otf) format("opentype")}@font-face{font-family:Amaranth;font-style:italic;src:url(../fonts/Amaranth-Italic.otf) format("opentype")}@font-face{font-family:Amaranth;font-style:italic;font-weight:700;src:url(../fonts/Amaranth-BoldItalic.otf) format("opentyp [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css.map b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css.map
index 406bc0e..9047842 100644
--- a/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-roxborough/npm/dist/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../scss/_custom.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_i [...]
\ No newline at end of file
+{"version":3,"sources":["../../scss/_custom.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_i [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css
index ca124e1..8e0ad10 100644
--- a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css
+++ b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css
@@ -10529,7 +10529,7 @@ h1 button.tobago-link, .h1 button.tobago-link, h2 button.tobago-link, .h2 button
   font-weight: inherit;
 }
 
-button.tobago-link, button.tobago-treeCommand {
+button.tobago-link {
   color: #0d6efd;
   border-width: 0;
   padding: 0;
@@ -10537,23 +10537,23 @@ button.tobago-link, button.tobago-treeCommand {
   text-align: left;
 }
 
-button.tobago-link:focus, button.tobago-link:hover, button.tobago-treeCommand:focus, button.tobago-treeCommand:hover {
+button.tobago-link:focus, button.tobago-link:hover {
   color: #024dbc;
   cursor: pointer;
   outline: none;
   text-decoration: underline;
 }
 
-button.tobago-link:disabled, button.tobago-treeCommand:disabled {
+button.tobago-link:disabled {
   color: #6c757d;
 }
 
-button.tobago-link:disabled:hover, button.tobago-treeCommand:disabled:hover {
+button.tobago-link:disabled:hover {
   cursor: not-allowed;
   text-decoration: none;
 }
 
-button.tobago-link:disabled > img, button.tobago-treeCommand:disabled > img {
+button.tobago-link:disabled > img {
   opacity: .65;
 }
 
@@ -10634,10 +10634,6 @@ a.tobago-messages-button, a.tobago-help-button, a.tobago-popover-button {
   margin-bottom: 0;
 }
 
-.tobago-flexLayout.tobago-messages-container > {
-  /* TODO: maybe add here some stuff for vaadin-combo-box-light for tc:tobago-suggest */
-}
-
 .tobago-flexLayout.tobago-messages-container > .tobago-input-group-outer, .tobago-flexLayout.tobago-messages-container > .tobago-selectManyShuttle {
   flex: 1 0 0px;
 }
@@ -11669,10 +11665,6 @@ tobago-tab-group {
   margin-right: 0.375rem;
 }
 
-.tobago-treeCommand {
-  cursor: pointer;
-}
-
 .tobago-treeNode[data-tobago-level] {
   margin-left: 7rem;
 }
diff --git a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css.map b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css.map
index 0989e9c..19a86c1 100644
--- a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../ [...]
\ No newline at end of file
+{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../ [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css
index 0af1175..76205a4 100644
--- a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto, [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto, [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css.map b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css.map
index be440e2..9db095f 100644
--- a/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-scarborough/npm/dist/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_mod [...]
\ No newline at end of file
+{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_mod [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css
index aea0846..13b8043 100644
--- a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css
+++ b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css
@@ -10209,7 +10209,7 @@ h1 button.tobago-link, .h1 button.tobago-link, h2 button.tobago-link, .h2 button
   font-weight: inherit;
 }
 
-button.tobago-link, button.tobago-treeCommand {
+button.tobago-link {
   color: #0d6efd;
   border-width: 0;
   padding: 0;
@@ -10217,23 +10217,23 @@ button.tobago-link, button.tobago-treeCommand {
   text-align: left;
 }
 
-button.tobago-link:focus, button.tobago-link:hover, button.tobago-treeCommand:focus, button.tobago-treeCommand:hover {
+button.tobago-link:focus, button.tobago-link:hover {
   color: #8a5318;
   cursor: pointer;
   outline: none;
   text-decoration: underline;
 }
 
-button.tobago-link:disabled, button.tobago-treeCommand:disabled {
+button.tobago-link:disabled {
   color: #d7d7d7;
 }
 
-button.tobago-link:disabled:hover, button.tobago-treeCommand:disabled:hover {
+button.tobago-link:disabled:hover {
   cursor: not-allowed;
   text-decoration: none;
 }
 
-button.tobago-link:disabled > img, button.tobago-treeCommand:disabled > img {
+button.tobago-link:disabled > img {
   opacity: .65;
 }
 
@@ -10314,10 +10314,6 @@ a.tobago-messages-button, a.tobago-help-button, a.tobago-popover-button {
   margin-bottom: 0;
 }
 
-.tobago-flexLayout.tobago-messages-container > {
-  /* TODO: maybe add here some stuff for vaadin-combo-box-light for tc:tobago-suggest */
-}
-
 .tobago-flexLayout.tobago-messages-container > .tobago-input-group-outer, .tobago-flexLayout.tobago-messages-container > .tobago-selectManyShuttle {
   flex: 1 0 0px;
 }
@@ -11349,10 +11345,6 @@ tobago-tab-group {
   margin-right: 0.375rem;
 }
 
-.tobago-treeCommand {
-  cursor: pointer;
-}
-
 .tobago-treeNode[data-tobago-level] {
   margin-left: 7rem;
 }
@@ -11789,12 +11781,12 @@ button.tobago-link > span {
   position: relative;
 }
 
-button.tobago-link, button.tobago-command, button.tobago-treeCommand {
+button.tobago-link, button.tobago-command {
   color: #ce8636;
   text-decoration: none;
 }
 
-button.tobago-link:focus, button.tobago-link:hover, button.tobago-command:focus, button.tobago-command:hover, button.tobago-treeCommand:focus, button.tobago-treeCommand:hover {
+button.tobago-link:focus, button.tobago-link:hover, button.tobago-command:focus, button.tobago-command:hover {
   color: #8a5318;
   text-decoration: none;
 }
@@ -11817,7 +11809,7 @@ button.tobago-link:focus, button.tobago-link:hover, button.tobago-command:focus,
   color: #fff;
 }
 
-td button.tobago-link, td button.tobago-command, td button.tobago-treeCommand {
+td button.tobago-link, td button.tobago-command {
   padding-top: 5px;
   margin-bottom: 12px;
 }
@@ -12287,7 +12279,7 @@ tobago-tab.tobago-tab-barFacet .nav-link.disabled + div {
   display: none;
 }
 
-a[disabled], button.tobago-link[disabled], button.tobago-command[disabled], button.tobago-treeCommand[disabled] {
+a[disabled], button.tobago-link[disabled], button.tobago-command[disabled] {
   color: #d7d7d7;
 }
 
diff --git a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css.map b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css.map
index c08f4df..d2bb2b7 100644
--- a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../scss/_custom.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.s [...]
\ No newline at end of file
+{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../scss/_custom.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.s [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css
index 067f427..45c6381 100644
--- a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#3a2564;--bs-pink:#d63384;--bs-red:#d30040;--bs-orange:#d90;--bs-yellow:#ffc107;--bs-green:#1da332;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#788c94;--bs-gray-dark:#323232;--bs-primary:#185722;--bs-secondary:#d7d7d7;--bs-success:#1da332;--bs-info:#5bc0de;--bs-warning:#f0ad4e;--bs-danger:#d30040;--bs-light:#f7f7f7;--bs-dark:#323232;--bs-font-sans-serif:verdana,sans-serif;--bs-font-monospace:SFMono [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#3a2564;--bs-pink:#d63384;--bs-red:#d30040;--bs-orange:#d90;--bs-yellow:#ffc107;--bs-green:#1da332;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#788c94;--bs-gray-dark:#323232;--bs-primary:#185722;--bs-secondary:#d7d7d7;--bs-success:#1da332;--bs-info:#5bc0de;--bs-warning:#f0ad4e;--bs-danger:#d30040;--bs-light:#f7f7f7;--bs-dark:#323232;--bs-font-sans-serif:verdana,sans-serif;--bs-font-monospace:SFMono [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css.map b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css.map
index 6c792ba..211df19 100644
--- a/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-speyside/npm/dist/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_modules/bootstrap/scss/_containers.scss","../../node_modules/boots [...]
\ No newline at end of file
+{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_modules/bootstrap/scss/_containers.scss","../../node_modules/boots [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/npm/scss/_speyside-overwrites.scss b/tobago-theme/tobago-theme-speyside/npm/scss/_speyside-overwrites.scss
index 3f9c60a..db059bb 100644
--- a/tobago-theme/tobago-theme-speyside/npm/scss/_speyside-overwrites.scss
+++ b/tobago-theme/tobago-theme-speyside/npm/scss/_speyside-overwrites.scss
@@ -91,7 +91,7 @@ button {
     }
   }
 
-  &.tobago-link, &.tobago-command, &.tobago-treeCommand {
+  &.tobago-link, &.tobago-command {
     color: $link-color;
     text-decoration: none;
 
@@ -121,7 +121,7 @@ button {
 }
 
 td button {
-  &.tobago-link, &.tobago-command, &.tobago-treeCommand {
+  &.tobago-link, &.tobago-command {
     padding-top: 5px;
     margin-bottom: 12px;
   }
@@ -664,7 +664,7 @@ tobago-tab.tobago-tab-barFacet {
   }
 }
 
-a, button.tobago-link, button.tobago-command, button.tobago-treeCommand {
+a, button.tobago-link, button.tobago-command {
   &[disabled] {
     color: $gray-300;
   }
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css
index d52e69a..271e99a 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css
+++ b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css
@@ -10490,7 +10490,7 @@ h1 button.tobago-link, .h1 button.tobago-link, h2 button.tobago-link, .h2 button
   font-weight: inherit;
 }
 
-button.tobago-link, button.tobago-treeCommand {
+button.tobago-link {
   color: #0d6efd;
   border-width: 0;
   padding: 0;
@@ -10498,23 +10498,23 @@ button.tobago-link, button.tobago-treeCommand {
   text-align: left;
 }
 
-button.tobago-link:focus, button.tobago-link:hover, button.tobago-treeCommand:focus, button.tobago-treeCommand:hover {
+button.tobago-link:focus, button.tobago-link:hover {
   color: #024dbc;
   cursor: pointer;
   outline: none;
   text-decoration: underline;
 }
 
-button.tobago-link:disabled, button.tobago-treeCommand:disabled {
+button.tobago-link:disabled {
   color: #6c757d;
 }
 
-button.tobago-link:disabled:hover, button.tobago-treeCommand:disabled:hover {
+button.tobago-link:disabled:hover {
   cursor: not-allowed;
   text-decoration: none;
 }
 
-button.tobago-link:disabled > img, button.tobago-treeCommand:disabled > img {
+button.tobago-link:disabled > img {
   opacity: .65;
 }
 
@@ -10595,10 +10595,6 @@ a.tobago-messages-button, a.tobago-help-button, a.tobago-popover-button {
   margin-bottom: 0;
 }
 
-.tobago-flexLayout.tobago-messages-container > {
-  /* TODO: maybe add here some stuff for vaadin-combo-box-light for tc:tobago-suggest */
-}
-
 .tobago-flexLayout.tobago-messages-container > .tobago-input-group-outer, .tobago-flexLayout.tobago-messages-container > .tobago-selectManyShuttle {
   flex: 1 0 0px;
 }
@@ -11630,10 +11626,6 @@ tobago-tab-group {
   margin-right: 0.375rem;
 }
 
-.tobago-treeCommand {
-  cursor: pointer;
-}
-
 .tobago-treeNode[data-tobago-level] {
   margin-left: 7rem;
 }
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css.map b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css.map
index 786e4a9..5ba9077 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../ [...]
\ No newline at end of file
+{"version":3,"sources":["tobago.css","../../scss/tobago-theme.scss","../../node_modules/bootstrap/scss/bootstrap.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_variables.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../ [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css
index 794a6b1..0429ef6 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto, [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto, [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css.map b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css.map
index 0b61ae3..c1c3ff5 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_mod [...]
\ No newline at end of file
+{"version":3,"sources":["../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/_reboot.scss","dist/css/tobago.css","../../node_modules/bootstrap/scss/vendor/_rfs.scss","tobago.css","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_mod [...]
\ No newline at end of file


Mime
View raw message