You must handle properties carefully due to the widget's lifecycle. When your constructor runs, the widget is in the wsCreating state, and its Handle is not yet fully initialized in the DOM. You cannot write to Handle.style at this stage.


The correct pattern is to cache the value in a private field, and then apply it when the widget is ready.


  • Define your property with a private field (e.g., fMyText).
  • Your setter method writes to fMyText if the widget is not ready. If it is ready (wsReady), it writes directly to the DOM Handle.
  • It is also important that you give all published properties a default value, even if it's just an empty string or 0 for int32 fields, this is used by the widget inspector in the IDE to know what the default values are
  • Override ApplyPropertyCache. This method is called by the TQTXWidget constructor at the exact moment the Handle is ready, but before your ObjectReady method is called. This is the place to apply all your cached values.


type

 TMyWidget = class(TQTXWidget)

 private

   fMyText: string;

 protected

   procedure SetMyText(Value: string);

   procedure ApplyPropertyCache; override;

 public

   // ... constructor ...

 published

   property MyText: string read fMyText write SetMyText;

 end;


procedure TMyWidget.SetMyText(Value: string);

begin

 if WidgetState = wsReady then

   Handle.innerText := Value  // Apply immediately if ready

 else

   fMyText := Value;          // Otherwise, cache the value

end;


procedure TMyWidget.ApplyPropertyCache;

begin

 inherited;

 // Apply all cached values to the newly created Handle

 SetMyText(fMyText);

end;


This pattern is used by all standard controls, such as TQTXCustomEdit for its fText and fReadOnly properties.