Skip to main content

Understanding Components

Open in ChatGPT
Java API

Before building custom components in webforJ, it's important to understand the foundational architecture that shapes how components work. This article explains the component hierarchy, component identity, lifecycle concepts, and how concern interfaces provide component capabilities.

Understanding the component hierarchy

webforJ organizes components into a hierarchy with two groups: framework internal classes you should never extend, and classes designed specifically for building custom components. This section explains why webforJ uses composition over inheritance and what each level of the hierarchy provides.

Why composition instead of extension?

In webforJ, built-in components like Button and TextField are final classes—you can't extend them:

// This won't work in webforJ
public class MyButton extends Button {
// Button is final - cannot be extended
}

webforJ uses composition over inheritance. Instead of extending existing components, you create a class that extends Composite and combines components inside it. Composite acts as a container that wraps a single component (called the bound component) and lets you add your own components and behavior to it.

public class SearchBar extends Composite<FlexLayout> {
private final FlexLayout self = getBoundComponent();
private TextField searchField;
private Button searchButton;

public SearchBar() {
searchField = new TextField("Search");
searchButton = new Button("Go");

self.setDirection(FlexDirection.ROW)
.add(searchField, searchButton);
}
}

Why you can't extend built-in components

webforJ components are marked as final to maintain the integrity of the underlying client-side web component. Extending webforJ component classes would grant control over the underlying web component, which could lead to unintended consequences and break the consistency and predictability of component behavior.

For a detailed explanation, see Final Classes and Extension Restrictions in the architecture documentation.

The component hierarchy

Classes for developers (use these):

  • Composite
  • ElementComposite
  • ElementCompositeContainer

Internal framework classes (never extend directly):

  • Component
  • DwcComponent
Never extend Component or DwcComponent

Never extend Component or DwcComponent directly. All built-in components are final. Always use composition patterns with Composite or ElementComposite.

Attempting to extend DwcComponent will throw a runtime exception.

Concern interfaces

Concern interfaces are Java interfaces that provide specific capabilities to your components. Each interface adds a set of related methods. For example, HasSize adds methods for controlling width and height, while HasFocus adds methods for managing focus state.

When you implement a concern interface on your component, you get access to those capabilities without writing any implementation code. The interface provides default implementations that work automatically.

Implementing concern interfaces gives your custom components the same APIs as built-in webforJ components:

// Implement HasSize to get width/height methods automatically
public class SizedCard extends Composite<Div> implements HasSize<SizedCard> {
private final Div self = getBoundComponent();

public SizedCard() {
self.setText("Card content");
}

// No need to implement these - you get them for free:
// setWidth(), setHeight(), setSize()
}

// Use it like any webforJ component
SizedCard card = new SizedCard();
card.setWidth("300px")
.setHeight("200px");

The composite automatically forwards these calls to the underlying Div. No extra code needed.

Appearance

These interfaces control the visual presentation of a component, including its dimensions, visibility, styling, and theme.

InterfaceDescription
HasSizeControls width and height, including min and max constraints. Extends HasWidth, HasHeight, and their min/max variants.
HasVisibilityShows or hides the component without removing it from the layout.
HasClassNameManages CSS class names on the component's root element.
HasStyleApplies and removes inline CSS styles.
HasHorizontalAlignmentControls how content is aligned horizontally within the component.
HasExpanseSets the component's size variant using the standard expanse tokens (XSMALL through XLARGE).
HasThemeApplies a theme variant such as DEFAULT, PRIMARY, or DANGER.
HasPrefixAndSuffixAdds components to the prefix or suffix slot inside the component.

Content

These interfaces manage what a component displays, including text, HTML, labels, hints, and other descriptive content.

InterfaceDescription
HasTextSets and retrieves the component's plain text content.
HasHtmlSets and retrieves the component's inner HTML.
HasLabelAdds a descriptive label associated with the component, used for accessibility.
HasHelperTextDisplays secondary hint text below the component.
HasPlaceholderSets placeholder text shown when the component has no value.
HasTooltipAttaches a tooltip that appears on hover.

State

These interfaces control the interactive state of a component, including whether it's enabled, editable, required, or focused on load.

InterfaceDescription
HasEnablementEnables or disables the component.
HasReadOnlyPuts the component into a read-only state where the value is visible but can't be changed.
HasRequiredMarks the component as required, typically for form validation.
HasAutoFocusMoves focus to the component automatically when the page loads.

Focus

These interfaces manage how a component receives and responds to keyboard focus.

InterfaceDescription
HasFocusManages focus state and whether the component can receive focus.
HasFocusStatusChecks whether the component currently has focus. Requires a round-trip to the client.
HasHighlightOnFocusControls whether the component's content is highlighted when it receives focus, and how (KEY, MOUSE, KEY_MOUSE, ALL, and so on).

Input constraints

These interfaces define what values a component accepts, including the current value, allowed ranges, length limits, formatting masks, and locale-specific behavior.

InterfaceDescription
HasValueGets and sets the component's current value.
HasMinSets a minimum allowed value.
HasMaxSets a maximum allowed value.
HasStepSets the step increment for numeric or range inputs.
HasPatternApplies a regular expression pattern to constrain accepted input.
HasMinLengthSets the minimum number of characters required in the component's value.
HasMaxLengthSets the maximum number of characters allowed in the component's value.
HasMaskApplies a format mask to the input. Used by masked field components.
HasTypingModeControls whether typed characters are inserted or overwrite existing characters (INSERT or OVERWRITE). Used by masked fields and TextArea.
HasRestoreValueDefines a value the component resets to when the user presses Escape or calls restoreValue(). Used by masked fields.
HasLocaleStores a per-component locale for locale-sensitive formatting. Used by masked date and time fields.
HasPredictedTextSets a predicted or auto-complete text value. Used by TextArea to support inline suggestions.

Validation

These interfaces add client-side validation behavior, including marking components invalid, displaying error messages, and controlling when validation runs.

InterfaceDescription
HasClientValidationMarks a component invalid, sets the error message, and attaches a client-side validator.
HasClientAutoValidationControls whether the component validates automatically as the user types.
HasClientAutoValidationOnLoadControls whether the component validates when it first loads.
HasClientValidationStyleControls how validation messages are displayed: INLINE (below the component) or POPOVER.

DOM access

These interfaces provide low-level access to the component's underlying HTML element and client-side properties.

InterfaceDescription
HasAttributeReads and writes arbitrary HTML attributes on the component's element.
HasPropertyReads and writes DWC component properties directly on the client element.

i18n

This interface provides translation support for components that need to display localized text.

InterfaceDescription
HasTranslationProvides the t() helper method for resolving translation keys to localized strings using the app's current locale.
warning

If the underlying component doesn't support the interface capability, you'll get a runtime exception. Provide your own implementation in that case.

For a complete list of available concern interfaces, see the webforJ JavaDoc.

Component lifecycle overview

webforJ manages the component lifecycle automatically. The framework handles component creation, attachment, and destruction without requiring manual intervention.

Lifecycle hooks are available when you need them:

  • onDidCreate(T container) - Called after the component is attached to the DOM
  • onDidDestroy() - Called when the component is destroyed

These hooks are optional. Use them when you need to:

  • Clean up resources (stop intervals, close connections)
  • Initialize components that require DOM attachment
  • Integrate with client-side JavaScript

For most simple cases, you can initialize components directly in the constructor. Use lifecycle hooks like onDidCreate() to defer work when necessary.