Modern CheckBoxes
by Erick Engelke
September 17, 2024
I was recently asked how to make a modern iOS-styled toggle in EWB.
You can find many examples of this sort of thing on the Web done with CSS and a checkbox and a dash of colour when checked.
The result looks like this:
I did not make a true EWB component, so you cannot use the IDE form designer with it.
But I did write the control and the sample application in less than 100 lines of Pascal.
I made it so you just have to define a containing THTMLLabel for each toggle and call AddModernCheckBox() to place the new control in that HTMLLabel.
procedure TForm1.Form1Show(Sender: TObject);
begin
moderncheckbox1 := AddModernCheckBox( htmllabel1 );
moderncheckbox2 := AddModernCheckBox( htmllabel2 );
// set the second one to true
moderncheckbox2.Checked := True;
// set the JavaScript-styled event handler
moderncheckbox1.OnChange := mcbchanged;
moderncheckbox2.OnChange := mcbchanged;
end;
You can read or write the Checked property to set or return whether the switch is activated.
And you can call a JavaScript-styled Event Hander (which is not identical to typical EWB event handlers in format).
My sample handler shows the state of the control which was just changed. In this sample app I have two of them, so change either for a popup.
function TForm1.mcbchanged( ev : TEvent ):integer;
var
mcb : TModernCheckBox;
begin
mcb := TModernCheckBox( ev.Target );
showmessage('new state of ' + mcb.id + ' : ' + BoolToStr( moderncheckbox1.Checked ) );
end;
You can move the control around the screen by changing the Left, Top properties of the THTMLLabel, or using its Layout properties.
Issues
There are numerous issues.
-
Much of the code is spent creating the CSS for this toggle switch. That’s quite ugly.
-
I didn’t spend a lot of time on this, it’s not a high priority to me, but it is cool and some people will find it useful.
-
You cannot use AutoHeight or AutoSize or it won’t work due to some internals of EWB. The code sets the dimensions in the AddModernCheckbox() function.
-
Many other typical EWB features are not present, including Dataset, etc.
Here’s the complete code, it just needs two THTMLLables, one for each TModernCheckBox created.
Here’s the complete Form.
unit moderntoggle;
interface
uses WebCore, webdom, WebUI, WebForms, WebCtrls, WebLabels, WebBtns;
type
TOnChangedFn = function( ev : TEvent ):integer of object;
external TModernCheckBox = class( TDOMElement)
public
property id : string read write;
property checked :boolean read write;
property onchange : TOnChangedFn read write;
end;
TForm1 = class(TForm)
HTMLLabel1: THTMLLabel;
HTMLLabel2: THTMLLabel;
procedure Form1Show(Sender: TObject);
private
{ Private declarations }
moderncheckbox1 : TModernCheckBox;
moderncheckbox2 : TModernCheckBox;
function mcbchanged( ev : TEvent ):integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
type
var
moderncheckboxoffset : integer = 0;
function AddModernCheckbox( lab : THTMLlabel ) : TModernCheckBox;
var
label : string;
begin
// grab next label
label := 'ModernCheckBox-'+IntToStr( moderncheckboxoffset );
inc( moderncheckboxoffset );
lab.Width := 70;
lab.Height := 40;
lab.Content :=
'<style>'+#13+#10+
' .switch{ opacity: 1; }'+#13+#10+
' .switch-btn{ width: 40px; height: 10px; background: #e5e5e5; position: relative; border-radius: 20px; box-shadow: inset 0 3px 10px rgba(0,0,0,.3); }'+#13+#10+
' .switch-btn:before{ content: ""; position: absolute; height: 19px; width: 19px; background: linear-gradient(#FFF, #f2f2f2); '+#13+#10+
' left: 2px; top: 50%; transition: all 250ms ease-out; cursor: pointer; border-radius: 50%; '+#13+#10+
' box-shadow: 0 8px 6px -4px rgba(0,0,0,.25); transform: translateY(-50%); }'+#13+#10+
' input[type=checkbox]:checked + .switch-btn { background: #47CB8F; } '+#13+#10+
' input[type=checkbox]:checked + .switch-btn:before { left: 19px; }'+#13+#10+
'</style>'+#13+#10+
'<label class="switch">'+#13+#10+
' <input id="'+ label + '" style="opacity:0;" type="checkbox"/> '+#13+#10+
' <div class="switch-btn"></div> '+#13+#10+
'</label>'+#13+#10;
result := TModernCheckBOx(window.document.getElementById( label ));
end;
function TForm1.mcbchanged( ev : TEvent ):integer;
var
mcb : TModernCheckBox;
begin
mcb := TModernCheckBox( ev.Target );
showmessage('new state of ' + mcb.id + ' : ' + BoolToStr( moderncheckbox1.Checked ) );
end;
procedure TForm1.Form1Show(Sender: TObject);
begin
moderncheckbox1 := AddModernCheckBox( htmllabel1 );
moderncheckbox2 := AddModernCheckBox( htmllabel2 );
// set it true
moderncheckbox2.Checked := True;
moderncheckbox1.OnChange := mcbchanged;
moderncheckbox2.OnChange := mcbchanged;
end;
end.
Erick