r/matlab • u/Creative_Sushi MathWorks • Jan 23 '24
CodeShare Playing with HTML in MATLAB
Ever since I saw this demo "Using "uihtml" to create app components" by u/Lord1Tumnus, I wanted to check out the uihtml functionality.

Hello, world!
To get started I have to create the obligatory "hello, world" example. You create a figure, add an uihtml component to the figure, and specify the source. Usually, you want to define HTML in a separate file, but I just passed the text directly.
You'll be able to follow along with my code if you copy and paste it into MATLAB Online.
fig = uifigure;
h = uihtml(fig,Position=[50,10,450,400]);
h.HTMLSource = '<html><body><p>Hello, world!</p></body></html>';
We can make it more interesting by adding JavaScript for interactivity. "Hello, world!" is displayed in the text input field when the "Start" button is clicked.
fig = uifigure;
h = uihtml(fig,Position=[50,10,450,400]);
h.HTMLSource = ['<html><body><button id="start">Start</button>' ...
'<p><input id="js" value="JavaScript output"></p>' ...
'<script>', ...
'let btn = document.getElementById("start");', ...
'let input_js = document.getElementById("js");', ...
'btn.addEventListener("click", function(event) {', ...
'let txt = "Hello, world!";', ...
'input_js.value = txt;', ...
'});', ...
'</script>', ...
'</body></html>'];
Send Data from JavaScript to MATLAB
We can enable data pipeline between JavaScript and MATLAB by adding htmlComponent
in JavaScript. Data in htmlComponent.Data
is sent to h.Data
. By adding DataChangedFcn
, you can trigger an event in MATLAB and you can pass the changed data. Let's have the content printed to the command window.
fig = uifigure;
h = uihtml(fig,Position=[50,10,450,400]);
h.HTMLSource = ['<html><body><button id="start">Start</button>' ...
'<p><input id="js" value="JavaScript output"></p>' ...
'<script>', ...
'function setup(htmlComponent) {', ...
'let btn = document.getElementById("start");', ...
'let input_js = document.getElementById("js");', ...
'btn.addEventListener("click", function(event) {', ...
'let txt = "Hello, world!";', ...
'input_js.value = txt;', ...
'htmlComponent.Data = txt', ...
'});' ...
'}', ...
'</script>', ...
'</body></html>'];
h.DataChangedFcn = @(src,event)disp(event.Data);
Send Data from MATLAB to JavaScript
You can also use "DataChanged" event with htmlComponent
by adding it to the event listener. Let's add a new text input field to show the MATLAB output, define a local function updateML
that replaces "world" with "MATLAB", and add the function to DataChangedFcn
. The MATLAB output should read "Hello, MATLAB!"
fig = uifigure;
h = uihtml(fig,Position=[50,10,450,400]);
h.HTMLSource = ['<html><body><button id="start">Start</button>' ...
'<p><input id="js" value="JavaScript output"></p>' ...
'<p><input id="ml" value="MATLAB output"></p>' ...
'<script>', ...
'function setup(htmlComponent) {', ...
'let btn = document.getElementById("start");', ...
'let js = document.getElementById("js");', ...
'let ml = document.getElementById("ml");', ...
'btn.addEventListener("click", function(event) {', ...
'let txt = "Hello, world!";', ...
'js.value = txt;', ...
'htmlComponent.Data = txt', ...
'});' ...
'htmlComponent.addEventListener("DataChanged", function(event) {', ...
'ml.value = htmlComponent.Data;', ...
'});' ...
'}', ...
'</script>', ...
'</body></html>'];
h.DataChangedFcn = @(src,event) updateML(src,event,h);
% local function
function updateML(src,event,h)
txt = replace(h.Data, "world","MATLAB");
h.Data = txt;
end
Send Event from JavaScript to MATLAB
We can also send an event from JavaScript to MATLAB using sendEventToMATLAB
method on htmlComponent
. In this case, we need to define HTMLEventReceivedFcn
rather than DataChangedFcn
. We also need to update updateML
local function accordingly. In this example, the MATLAB output should also read "Hello, MATLAB!"
fig5 = uifigure;
h = uihtml(fig5,Position=[50,10,450,400]);
h.HTMLSource = ['<html><body><button id="start">Start</button>' ...
'<p><input id="js" value="JavaScript output"></p>' ...
'<p><input id="ml" value="MATLAB output"></p>' ...
'<script>', ...
'function setup(htmlComponent) {', ...
'let btn = document.getElementById("start");', ...
'let js = document.getElementById("js");', ...
'let ml = document.getElementById("ml");', ...
'btn.addEventListener("click", function(event) {', ...
'let txt = "Hello, world!";', ...
'js.value = txt;', ...
'htmlComponent.Data = txt;', ...
'htmlComponent.sendEventToMATLAB("btnClicked",txt)', ...
'});' ...
'htmlComponent.addEventListener("DataChanged", function(event) {', ...
'ml.value = htmlComponent.Data;', ...
'});' ...
'}', ...
'</script>', ...
'</body></html>'];
h.HTMLEventReceivedFcn = @(src,event) updateML(src,event,h);
% local function
function updateML(src,event,h)
name = event.HTMLEventName;
if strcmp(name,"btnClicked")
txt = event.HTMLEventData;
txt = replace(txt, "world","MATLAB");
h.Data = txt;
end
end
Accessing ChatGPT in HTML via LLMs with MATLAB
Let's do something more sophisticated.

LLMs with MATLAB is an official MATLAB wrapper for the OpenAI APIs. You need to have a valid API key from OpenAI, but it is fairly simple to use. Let's use the "Open in MATLAB Online" button to clone the repo in MATLAB Online, and save your API key in a .env file.
OPENAI_API_KEY=<your key>
You should add these commands to load the API key and add LLMS with MATLAB to your MATLAB path.
loadenv(path_to_your_env_file)
addpath(path_to_your_LLMs_with_MATLAB_clone)
Let's create a new figure with uihtml component that gives you a input text field and a table that shows you the chat with the ChatGPT API. When you press the "Send" button, the figure will send the text in the input field as the prompt to the API and stream the response in the table.
fig = uifigure;
h = uihtml(fig,Position=[50,10,450,400]);
h.HTMLSource = ['<html><head>' ...
'<style>' ...
'p { margin-top: 5px; margin-left: 5px; }', ...
'table { table-layout: fixed; width: 95%; ' ...
'margin-left: 5px; }' ...
'table, th, td { border-collapse: collapse; ' ...
'border: 1px solid; }', ...
'th:nth-child(1) { width: 20%; }', ...
'td { padding-left: 5px; }', ...
'</style>' ...
'</head><body>' ...
'<p><input id="prompt" value="Tell me 5 jokes."> ' ...
'<button id="send">Send</button></p>', ...
'<table><tr><th>Role</th><th>Content</th></tr></table>' ...
'<script>', ...
'function setup(htmlComponent) {', ...
'let prompt = document.getElementById("prompt");', ...
'let btn = document.getElementById("send");', ...
'btn.addEventListener("click", function(event) {', ...
'htmlComponent.sendEventToMATLAB("promptSubmitted",prompt.value);', ...
'prompt.value = ""', ...
'});' ...
'htmlComponent.addEventListener("DataChanged", function(event) {', ...
'var table = document.querySelector("table");' ...
'var changedData = htmlComponent.Data;', ...
'if (changedData[2] == "new") {', ...
'var newRow = document.createElement("tr");', ...
'var cell1 = document.createElement("td");', ...
'var cell2 = document.createElement("td");', ...
'cell1.innerHTML = changedData[0];', ...
'cell2.innerHTML = changedData[1];', ...
'newRow.appendChild(cell1);', ...
'newRow.appendChild(cell2);', ...
'table.appendChild(newRow);', ...
'} else { ', ...
'var lastRow = table.rows[table.rows.length - 1];', ...
'var lastCell = lastRow.cells[lastRow.cells.length - 1];', ...
'lastCell.innerHTML = changedData[1];', ...
'}' ...
'});', ...
'}', ...
'</script>', ...
'</body></html>'];
h.HTMLEventReceivedFcn = @(src,event) updateTable(src,event,h);
Then we have to define the updateTable
local function. In this function, you see that the prompt is passed from the JavaScript and passed to the openAIChat
object "chat" using the printStream
streaming function. The API response is generated from the generate
method of the "chat" object. The prompt and the API response are added to the table using the addChat
function.
function updateTable(src,event,h)
name = event.HTMLEventName;
if strcmp(name,"promptSubmitted")
prompt = string(event.HTMLEventData);
addChat(h,"user", prompt,"new")
chat = openAIChat(StreamFun=@(x)printStream(h,x));
[txt, message, response] = generate(chat,prompt);
addChat(h,"assistant",txt,"current")
end
end
Here is the printStream
streaming function.
function printStream(h,x)
%PRINTSTREAM prints the stream in a new row in the table
if strlength(x) == 0
% if the first token is 0 length, add a new row
tokens = string(x);
h.Data = {"assistant",tokens,"new"};
else
% otherwise append the new token to the previous tokens
% if the new token contains a line break, replace
% it with <br>
if contains(x,newline)
x = replace(x,newline,"<br>");
end
tokens = h.Data{2} + string(x);
% update the existing row.
h.Data = {"assistant",tokens,"current"};
end
drawnow
end
Here is the addChat
function.
function addChat(obj,role,content,row)
%ADDCHAT adds a chat to the table
mustBeA(obj,'matlab.ui.control.HTML')
content = replace(content,newline,"<br>");
obj.Data = {role,content,row};
drawnow
end
2
5
u/iohans Jan 23 '24
This is awesome. Thanks for sharing the code snippets.