UI Widgets in Earth Engine

Earth Engine's UI library lets you build interactive applications with buttons, sliders, dropdowns, and more. This module covers the core widgets you need to create user-friendly apps.

Learning objectives

  • Create buttons, sliders, textboxes, and select widgets.
  • Handle widget events (onClick, onChange).
  • Organize widgets in panels with layouts.
  • Update the map based on user interactions.

Why it matters

Interactive controls let non-coders explore your analysis. A slider to change thresholds, a dropdown to select dates—these turn static scripts into powerful tools anyone can use.

Key vocabulary

Widget
An interactive UI element (button, slider, label, etc.).
Panel
A container that holds and organizes multiple widgets.
Callback
A function that runs when a widget event occurs (click, change).
ui.root
The root container for all UI elements in an Earth Engine app.

Quick win: Interactive NDVI threshold

This example creates a slider that updates the NDVI threshold in real-time:

// Load a Landsat image
var image = ee.Image('LANDSAT/LC08/C02/T1_L2/LC08_044034_20210623')
  .multiply(0.0000275).add(-0.2);
var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI');

// Center and add base layer
Map.centerObject(image, 10);
Map.addLayer(ndvi, {min: 0, max: 0.8, palette: ['brown', 'yellow', 'green']}, 'NDVI');

// Create a slider widget
var slider = ui.Slider({
  min: 0,
  max: 1,
  value: 0.3,
  step: 0.05,
  style: {width: '300px'}
});

// Create a label to show current value
var label = ui.Label('Threshold: 0.3');

// Define callback function
var updateThreshold = function(value) {
  // Update label
  label.setValue('Threshold: ' + value.toFixed(2));
  
  // Remove old mask layer
  var layers = Map.layers();
  if (layers.length() > 1) {
    layers.remove(layers.get(1));
  }
  
  // Create and add new mask
  var mask = ndvi.gte(value);
  Map.addLayer(mask.updateMask(mask), {palette: ['00ff00']}, 'NDVI >= ' + value);
};

// Connect slider to callback
slider.onSlide(updateThreshold);

// Create panel and add to map
var panel = ui.Panel({
  widgets: [ui.Label('NDVI Threshold Selector'), slider, label],
  style: {position: 'top-left', padding: '8px'}
});
Map.add(panel);

What you should see

A panel with a slider appears on the map. Moving the slider updates the green mask showing pixels above the selected NDVI threshold.

Widget reference

Widget Purpose Key Event
ui.Label() Display text —
ui.Button() Trigger actions onClick()
ui.Slider() Select numeric value onSlide()
ui.Textbox() Text input onChange()
ui.Select() Dropdown menu onChange()
ui.Checkbox() Toggle option onChange()
ui.DateSlider() Select date range onChange()
ui.Chart Display charts —

More examples

Button

var button = ui.Button({
  label: 'Run Analysis',
  onClick: function() {
    print('Button clicked!');
    // Add your analysis code here
  }
});
Map.add(button);

Select (Dropdown)

var select = ui.Select({
  items: ['Landsat 8', 'Landsat 9', 'Sentinel-2'],
  value: 'Landsat 8',
  onChange: function(selected) {
    print('Selected:', selected);
  }
});
Map.add(select);

Textbox

var textbox = ui.Textbox({
  placeholder: 'Enter coordinates...',
  onChange: function(text) {
    print('User entered:', text);
  }
});
Map.add(textbox);

DateSlider

var dateSlider = ui.DateSlider({
  start: '2020-01-01',
  end: '2023-12-31',
  value: '2023-06-01',
  onChange: function(range) {
    print('Date range:', range.start(), range.end());
  }
});
Map.add(dateSlider);

Panel layouts

Use panels to organize widgets together:

// Vertical panel (default)
var verticalPanel = ui.Panel({
  widgets: [
    ui.Label('Title'),
    ui.Slider({min: 0, max: 100}),
    ui.Button('Submit')
  ],
  layout: ui.Panel.Layout.flow('vertical')
});

// Horizontal panel
var horizontalPanel = ui.Panel({
  widgets: [
    ui.Button('Option A'),
    ui.Button('Option B'),
    ui.Button('Option C')
  ],
  layout: ui.Panel.Layout.flow('horizontal')
});

// Add panel to map sidebar
ui.root.insert(0, verticalPanel);

Pro tips

  • Use ui.root.clear() + ui.root.add() for full-screen apps.
  • Style widgets with style: {width: '200px', color: 'red'}.
  • Use widget.setDisabled(true) to prevent interaction during processing.
  • Nest panels for complex layouts (sidebar with sections).
  • Test on different screen sizes before publishing.

Try it: Build a layer toggle

Create checkboxes that show/hide different map layers:

// Add layers
Map.addLayer(ndvi, {min:0, max:0.8, palette:['brown','green']}, 'NDVI', true);
Map.addLayer(image, {bands:['SR_B4','SR_B3','SR_B2'], min:0, max:0.3}, 'RGB', false);

// Create checkboxes
var ndviCheck = ui.Checkbox('Show NDVI', true);
ndviCheck.onChange(function(checked) {
  Map.layers().get(0).setShown(checked);
});

var rgbCheck = ui.Checkbox('Show RGB', false);
rgbCheck.onChange(function(checked) {
  Map.layers().get(1).setShown(checked);
});

Map.add(ui.Panel([ndviCheck, rgbCheck]));

Common mistakes

  • Forgetting to connect the callback function (onClick, onSlide).
  • Using client-side loops inside server-side callbacks.
  • Not removing old layers before adding new ones (layer pile-up).
  • Making panels too wide for the map area.
  • Hardcoding values instead of reading from widgets.

Quick self-check

  1. What event does a slider use: onClick or onSlide?
  2. How do you create a dropdown menu?
  3. What is the purpose of ui.Panel?
  4. How do you add a panel to the map interface?

Next steps

Going Deeper: EEFA Book

This module gives you the foundation. To explore further, see Chapter F6.2 (Earth Engine Apps) in the Cloud-Based Remote Sensing with Google Earth Engine (EEFA Book).