---
name: MATLAB uihtml App Builder
slug: matlab-uihtml-app-builder
category: Frontend
description: MATLAB uihtml App Builder builds interactive web UIs in HTML, JavaScript, and MATLAB using the uihtml component. Use it for MATLAB apps that need browser-based interfaces, event handling, and data exchange between JavaScript and MATLAB.
github: "https://github.com/matlab/agent-skills-playground/tree/main/skills/matlab-uihtml-app-builder"
language: HTML
stars: 175
forks: 32
install: "npx degit https://github.com/matlab/agent-skills-playground/tree/main/skills/matlab-uihtml-app-builder ~/.claude/skills/matlab-uihtml-app-builder"
installs_to: ~/.claude/skills/matlab-uihtml-app-builder
source_path: skills/matlab-uihtml-app-builder/SKILL.md
collection_size: 24
category_size: 705
collection_url: "https://dirskills.com/collections/matlab/agent-skills-playground"
added: 2026-09-07T05:21:27.951Z
last_synced: 2026-09-07T05:21:27.951Z
canonical_url: "https://dirskills.com/skills/matlab-uihtml-app-builder"
---

# MATLAB uihtml App Builder

MATLAB uihtml App Builder builds interactive web UIs in HTML, JavaScript, and MATLAB using the uihtml component. Use it for MATLAB apps that need browser-based interfaces, event handling, and data exchange between JavaScript and MATLAB.

**Install:**

```bash
npx degit https://github.com/matlab/agent-skills-playground/tree/main/skills/matlab-uihtml-app-builder ~/.claude/skills/matlab-uihtml-app-builder
```

## README

# MATLAB uihtml App Builder

This skill covers how to build interactive web applications that combine HTML/JavaScript interfaces with MATLAB computational backends using the uihtml component. The HTML side handles the UI; MATLAB does the computation.

## When to Use This Skill

- Building interactive MATLAB apps with HTML/JavaScript interfaces
- Creating web-based UIs for MATLAB applications
- Building responsive MATLAB GUIs with HTML/CSS/JS
- When user mentions: uihtml, HTML, JavaScript, web app, web interface, interactive GUI
- Combining web UI design with MATLAB computational power
- Creating calculator apps, data visualizers, or form-based MATLAB tools

## Core Architecture

### The Four Components

1. **HTML Interface** - User interface with buttons, forms, displays
2. **JavaScript Logic** - Event handling and UI interactions
3. **MATLAB Backend** - Computational engine and data processing
4. **uihtml Component** - Bridge between HTML and MATLAB

### Communication Patterns

The uihtml component enables bidirectional communication between JavaScript and MATLAB through several mechanisms:

#### Pattern 1: MATLAB → JavaScript (Data Property)

**Use Case**: Sending data from MATLAB to update the HTML interface

```matlab
% MATLAB side
h.Data = "Hello World!";
```

```javascript
// JavaScript side
htmlComponent.addEventListener("DataChanged", function(event) {
    document.getElementById("display").innerHTML = htmlComponent.Data;
});
```

#### Pattern 2: JavaScript → MATLAB (Events)

**Use Case**: Triggering MATLAB functions from user interactions

```javascript
// JavaScript side - send event to MATLAB
htmlComponent.sendEventToMATLAB("Calculate", expression);
```

```matlab
% MATLAB side - receive and handle event
h.HTMLEventReceivedFcn = @handleEvent;

function handleEvent(src, event)
    eventName = event.HTMLEventName;
    eventData = event.HTMLEventData;
    % Process event...
end
```

#### Pattern 3: MATLAB → JavaScript (Custom Events)

**Use Case**: Sending computed results or status updates to JavaScript

```matlab
% MATLAB side - send custom event to JavaScript
sendEventToHTMLSource(h, "ResultChanged", result);
```

```javascript
// JavaScript side - listen for custom event
htmlComponent.addEventListener("ResultChanged", function(event) {
    document.getElementById("display").textContent = event.Data;
});
```

#### Pattern 4: Complex Data Transfer

**Use Case**: Passing structured data between MATLAB and JavaScript

```matlab
% MATLAB side - struct data gets JSON encoded automatically
itemData = struct("ItemName","Apple","Price",2,"Quantity",10);
h.Data = itemData;
```

```javascript
// JavaScript side - access as object properties
htmlComponent.Data.ItemName  // "Apple"
htmlComponent.Data.Price     // 2
htmlComponent.Data.Quantity  // 10
```

**Important: decoding is automatic in both directions.**

- A JS object sent via `sendEventToMATLAB` arrives on `event.HTMLEventData` already converted to a MATLAB struct. **Do not call `jsondecode`**; it will fail on a struct.
- A MATLAB struct sent via `sendEventToHTMLSource` arrives on `event.Data` already as a JavaScript object. **Do not call `JSON.parse`**; it will fail on an object.
- Field names round-trip exactly: a JS `{x0: 1}` becomes a MATLAB `struct('x0', 1)`, not `struct('x_0', ...)` or similar.
- Numeric scalars arrive as MATLAB `double`. Wrap field reads with `double(data.x0)` if you want to be defensive about types.

## Critical Rules

### Security Requirements

- **ALWAYS** set `HTMLSource = 'trusted'` when using local HTML files:
  ```matlab
  h.HTMLSource = fullfile(pwd, 'myapp.html');
  % This is treated as trusted automatically for local files
  ```

- **MUST** validate all input from JavaScript before processing in MATLAB
- **NEVER** use `eval()` on user input without strict sanitization
- **ALWAYS** restrict allowed characters in user input for expressions

### Error Handling

**ALWAYS wrap MATLAB event handlers in try-catch blocks:**

```matlab
function handleEvent(src, event)
    eventName = event.HTMLEventName;
    eventData = event.HTMLEventData;

    try
        % Process the event
        result = processData(eventData);

        % Send result back to JavaScript
        sendEventToHTMLSource(src, 'ResultEvent', result);

    catch ME
        % Handle errors gracefully
        fprintf('Error: %s\n', ME.message);
        sendEventToHTMLSource(src, 'ErrorEvent', ME.message);
    end
end
```

### Data Validation

**ALWAYS validate user input before processing:**

```matlab
function result = validateExpression(expression)
    allowedChars = '0123456789+-*/.() ';
    if ~all(ismember(expression, allowedChars))
        error('Invalid characters in expression');
    end
    % Additional validation...
    result = true;
end
```

### File Organization

**Follow this directory structure:**

```
project/
├── app.m           # Main MATLAB function
├── app.html        # HTML interface
├── README.md       # Usage instructions
└── examples/       # Additional examples (optional)
```

## Complete Examples

### Example 1: Simple Calculator App

**MATLAB Side (calculator.m):**

```matlab
function calculator()
    % Create main figure
    fig = uifigure('Name', 'Calculator', 'Position', [100 100 400 500]);

    % Create HTML component
    h = uihtml(fig, 'Position', [25 25 350 450]);
    h.HTMLSource = fullfile(pwd, 'calculator.html');
    h.HTMLEventReceivedFcn = @(src, event) handleEvent(src, event);
end

function handleEvent(src, event)
    eventName = event.HTMLEventName;
    eventData = event.HTMLEventData;

    try
        switch eventName
            case 'Calculate'
                % Validate input
                expression = char(eventData);
                allowedChars = '0123456789+-*/.() ';

                if ~all(ismember(expression, allowedChars))
                    error('Invalid characters in expression');
                end

                % Evaluate safely
                result = eval(expression);

                % Send result back
                sendEventToHTMLSource(src, 'Result', num2str(result));

            case 'Clear'
                sendEventToHTMLSource(src, 'Result', '0');
        end

    catch ME
        fprintf('Error: %s\n', ME.message);
        sendEventToHTMLSource(src, 'Error', 'Invalid expression');
    end
end
```

**HTML Side (calculator.html):**

```html
<!DOCTYPE html>
<html>
<head>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            margin: 0;
            padding: 20px;
        }

        .calculator {
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.3);
        }

        .display {
            width: 100%;
            height: 60px;
            font-size: 24px;
            text-align: right;
            padding: 10px;
            border: 2px solid #ccc;
            border-radius: 5px;
            margin-bottom: 10px;
            background: #f9f9f9;
        }

        .buttons {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 10px;
        }

        button {
            padding: 20px;
            font-size: 18px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            background: #667eea;
            color: white;
            transition: background 0.3s;
        }

        button:hover {
            background: #764ba2;
        }

        .operator {
            background: #ff6b6b;
        }

        .operator:hover {
            background: #ee5a52;
        }
    </style>

    <script type="text/javascript">
        let currentExpression = '';

        function setup(htmlComponent) {
            window.htmlComponent = htmlComponent;

            // Listen for results from MATLAB
            htmlComponent.addEventListener("Result", function(event) {
                document.getElementById("display").value = event.Data;
                currentExpression = event.Data;
            });

            htmlComponent.addEventListener("Error", function(event) {
                document.getElementById("display").value = "Error";
                currentExpression = '';
            });
        }

        function appendToDisplay(value) {
            currentExpression += value;
            document.getElementById("display").value = currentExpression;
        }

        function clearDisplay() {
            currentExpression = '';
            document.getElementById("display").value = '0';
            window.htmlComponent.sendEventToMATLAB("Clear", "");
        }

        function calculate() {
            if (currentExpression) {
                window.htmlComponent.sendEventToMATLAB("Calculate", currentExpression);
            }
        }
    </script>
</head>
<body>
    <div class="calculator">
        <input type="text" id="display" class="display" value="0" readonly>
        <div class="buttons">
            <button onclick="appendToDisplay('7')">7</button>
            <button onclick="appendToDisplay('8')">8</button>
            <button onclick="appendToDisplay('9')">9</button>
            <button class="operator" onclick="appendToDisplay('/')">/</button>

            <button onclick="appendToDisplay('4')">4</button>
            <button onclick="appendToDisplay('5')">5</button>
            <button onclick="appendToDisplay('6')">6</button>
            <button class="operator" onclick="appendToDisplay('*')">*</button>

            <button onclick="appendToDisplay('1')">1</button>
            <button onclick="appendToDisplay('2')">2</button>
            <button onclick="appendToDisplay('3')">3</button>
            <button class="operator" onclick="appendToDisplay('-')">-</button>

            <button onclick="appendToDisplay('0')">0</button>
            <button onclick="appendToDisplay('.')">.</button>
            <button onclick="calculate()">=</button>
            <button class="operator" onclick="appendToDisplay('+')">+</button>

            <button style="grid-column: span 4; background: #ff6b6b;" onclick="clearDisplay()">Clear</button>
        </div>
    </div>
</body>
</html>
```

### Example 2: Data Visualization App

**MATLAB Side (visualizer.m):**

```matlab
function visualizer()
    fig = uifigure('Name', 'Data Visualizer', 'Position', [100 100 800 600]);

    % Create HTML component for controls
    h = uihtml(fig, 'Position', [25 400 750 175]);
    h.HTMLSource = fullfile(pwd, 'controls.html');
    h.HTMLEventReceivedFcn = @(src, event) handleEvent(src, event, fig);

    % Create axes for plotting
    ax = uiaxes(fig, 'Position', [25 25 750 350]);
    xlabel(ax, 'X');
    ylabel(ax, 'Y');
    title(ax, 'Interactive Plot');
end

function handleEvent(src, event, fig)
    eventName = event.HTMLEventName;
    eventData = event.HTMLEventData;

    try
        switch eventName
            case 'UpdatePlot'
                % Parse parameters from JavaScript
                params = eventData;
                frequency = params.frequency;
                amplitude = params.amplitude;
                plotType = params.plotType;

                % Generate data
                x = linspace(0, 4*pi, 200);

                switch plotType
                    case 'sine'
                        y = amplitude * sin(frequency * x);
                    case 'cosine'
                        y = amplitude * cos(frequency * x);
                    case 'both'
                        y = amplitude * sin(frequency * x);
                        y2 = amplitude * cos(frequency * x);
                end

                % Find axes and plot
                ax = findobj(fig, 'Type', 'axes');
                cla(ax);

                if strcmp(plotType, 'both')
                    plot(ax, x, y, 'LineWidth', 2);
                    hold(ax, 'on');
                    plot(ax, x, y2, 'LineWidth', 2);
                    hold(ax, 'off');
                    legend(ax, 'Sine', 'Cosine');
                else
                    plot(ax, x, y, 'LineWidth', 2);
                end

                grid(ax, 'on');

                % Send confirmation
                sendEventToHTMLSource(src, 'PlotUpdated', 'Success');
        end

    catch ME
        fprintf('Error: %s\n', ME.message);
        sendEventToHTMLSource(src, 'Error', ME.message);
    end
end
```

**HTML Side (controls.html):**

```html
<!DOCTYPE html>
<html>
<head>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
            color: white;
            margin: 0;
            padding: 20px;
        }

        .controls {
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            gap: 20px;
        }

        .control-group {
            background: rgba(255,255,255,0.1);
            padding: 15px;
            border-radius: 8px;
        }

        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }

        input[type="range"] {
            width: 100%;
        }

        select, button {
            width: 100%;
            padding: 8px;
            border-radius: 5px;
            border: none;
            font-size: 14px;
        }

        button {
            background: #3498db;
            color: white;
            cursor: pointer;
            margin-top: 10px;
            transition: background 0.3s;
        }

        button:hover {
            background: #2980b9;
        }
    </style>

    <script type="text/javascript">
        function setup(htmlComponent) {
            window.htmlComponent = htmlComponent;

            htmlComponent.addEventListener("PlotUpdated", function(event) {
                console.log("Plot updated successfully");
            });
        }

        function updatePlot() {
            const frequency = parseFloat(document.getElementById("frequency").value);
            const amplitude = parseFloat(document.getElementById("amplitude").value);
            const plotType = document.getElementById("plotType").value;

            const params = {
                frequency: frequency,
                amplitude: amplitude,
                plotType: plotType
            };

            window.htmlComponent.sendEventToMATLAB("UpdatePlot", params);
        }

        function updateFreqLabel(value) {
            document.getElementById("freqValue").textContent = value;
        }

        function updateAmpLabel(value) {
            document.getElementById("ampValue").textContent = value;
        }
    </script>
</head>
<body>
    <div class="controls">
        <div class="control-group">
            <label>Frequency: <span id="freqValue">1</span></label>
            <input type="range" id="frequency" min="0.1" max="5" step="0.1" value="1"
                   oninput="updateFreqLabel(this.value)">
        </div>

        <div class="control-group">
            <label>Amplitude: <span id="ampValue">1</span></label>
            <input type="range" id="amplitude" min="0.1" max="5" step="0.1" value="1"
                   oninput="updateAmpLabel(this.value)">
        </div>

        <div class="control-group">
            <label>Plot Type:</label>
            <select id="plotType">
                <option value="sine">Sine</option>
                <option value="cosine">Cosine</option>
                <option value="both">Both</option>
            </select>
        </div>
    </div>

    <button onclick="updatePlot()">Update Plot</button>
</body>
</html>
```

### Example 3: Form Processing App

**MATLAB Side (formProcessor.m):**

```matlab
function formProcessor()
    fig = uifigure('Name', 'Form Processor', 'Position', [100 100 600 400]);

    h = uihtml(fig, 'Position', [25 25 550 350]);
    h.HTMLSource = fullfile(pwd, 'form.html');
    h.HTMLEventReceivedFcn = @(src, event) handleEvent(src, event);
end

function handleEvent(src, event)
    eventName = event.HTMLEventName;
    eventData = event.HTMLEventData;

    try
        switch eventName
            case 'SubmitForm'
                % Extract form data
                name = eventData.name;
                email = eventData.email;
                age = eventData.age;

                % Validate data
                if isempty(name) || isempty(email)
                    error('Name and email are required');
                end

                if ~contains(email, '@')
                    error('Invalid email address');
                end

                if age < 0 || age > 120
                    error('Invalid age');
                end

                % Process data (example: save to file or database)
                fprintf('Processing form:\n');
                fprintf('  Name: %s\n', name);
                fprintf('  Email: %s\n', email);
                fprintf('  Age: %d\n', age);

                % Send success message
                result = struct('status', 'success', ...
                               'message', 'Form submitted');
                sendEventToHTMLSource(src, 'FormResult', result);

            case 'ClearForm'
                sendEventToHTMLSource(src, 'FormCleared', '');
        end

    catch ME
        fprintf('Error: %s\n', ME.message);
        result = struct('status', 'error', 'message', ME.message);
        sendEventToHTMLSource(src, 'FormResult', result);
    end
end
```

## Best Practices

### UI Design Principles

> The HTML in the examples below is deliberately minimal to keep the focus on the **MATLAB↔JS wiring**. The inline styling (Arial, `#667eea → #764ba2` purple-blue gradients, generic cards) is *not* a design reference. Those are exactly the "AI slop" tells to avoid. For any panel a user will actually see, take the visual system from `matlab-uihtml-design` and follow its **Design Guardrails**.

- **Use CSS Grid or Flexbox** for responsive layouts that adapt to different window sizes. Flexbox for 1D, Grid for 2D; don't default to Grid when `flex-wrap` is simpler
- **Implement hover effects** for better user experience and visual feedback
- **Provide clear visual feedback** for user actions (button clicks, form submission, errors), plus a visible `:focus-visible` state for keyboard users
- **Use semantic HTML elements** (button, input, form) for better accessibility
- **Pick a color scheme deliberately** (see `matlab-uihtml-design` for ready-made styles). Avoid the default reflexes: Inter/Roboto/Arial fonts, purple-to-blue gradients, side-stripe `border-left` accents, gradient text, and over-rounded (≥32px) cards
- **Verify contrast**: body/label text ≥4.5:1, large text and UI boundaries ≥3:1. Give numeric readouts `font-variant-numeric: tabular-nums` so values don't jitter width
- **Respect reduced motion**: wrap non-essential animation in `@media (prefers-reduced-motion: reduce)` with a crossfade/instant fallback

### Performance Optimization

- **Minimize data transfer** between HTML and MATLAB - send only necessary data
- **Use appropriate data types** - numbers, strings, structs (converted to JSON)
- **Implement loading indicators** for long MATLAB operations
- **Cache results** when appropriate using persistent variables in MATLAB
- **Batch multiple updates** instead of sending many small events

### Error Handling Strategy

**JavaScript Side:**
```javascript
htmlComponent.addEventListener("Error", function(event) {
    // Display user-friendly error messages
    alert("Error: " + event.Data);
});
```

**MATLAB Side:**
```matlab
try
    result = processInput(input);
    sendEventToHTMLSource(src, 'Success', result);
catch ME
    fprintf('Error: %s\n', ME.message);
    sendEventToHTMLSource(src, 'Error', 'Processing failed');
end
```

### Testing Strategy

1. **Unit Testing** - Test MATLAB functions independently
   ```matlab
   % Test individual processing 
