Panels and Layouts


A ui.Panel is an upper-level UI container in which to arrange widgets. Each ui.Panel has a ui.Panel.Layout object that controls how its widgets are arranged on the screen. Learn more in the Layouts section. Panels also maintain a list of widgets (which could include other panels) that have been added to them. To manage widgets in the panel, either add() or remove() them from the panel, or retrieve the list of widgets by calling widgets() on the panel. The widgets list is an instance of, which means that you can configure the panel by manipulating the list and the widgets in it.


The ui.root is a fixed instance of a ui.Panel for everything in the Code Editor below the horizontal bar. By default, it contains only a single widget: the default map. Specifically, the item at ui.root.widgets().get(0) is the Map object (an instance of ui.Map) that is displayed by default in the Code Editor). In addition to the Map alias, the only other special thing about the default Map is that it has geometry editing tools in it. To obtain an empty canvas in which to build your UI, clear() the default map out of ui.root:

Code Editor (JavaScript)


Alternatively, it's possible to modify the default map in the root panel by adding widgets to it. Specifically, think of a map as a panel with an absolute layout (see the Layouts section for details). The following example illustrates a modification of the default map:

Code Editor (JavaScript)

// Load a VIIRS surface reflectance image and display on the map.
var image = ee.Image('NOAA/VIIRS/001/VNP09GA/2022_06_05').select('M.*');
Map.addLayer(image, {bands: ['M5', 'M4', 'M3'], min: 0, max: 4e3, gamma: 1.5});

// Create the title label.
var title = ui.Label('Click to inspect');'position', 'top-center');

// Create a panel to hold the chart.
var panel = ui.Panel();{
  width: '400px',
  position: 'bottom-right'

// Register a function to draw a chart when a user clicks on the map.'cursor', 'crosshair');
Map.onClick(function(coords) {
  var point = ee.Geometry.Point(coords.lon,;
  var chart = ui.Chart.image.regions(image, point, null, 30);
  chart.setOptions({title: 'Band values'});

Note that the example modifies the default map (which is Map) by treating it as a panel and adding widgets to it. Because maps have absolute layout, the position of a widget on a map is determined by a position property of the style property of the widget. See the absolute layout section for details.

When you share a Code Editor link with another user, by default the ui.root takes up most of the window, and the text editor, docs panel, and console are hidden. By controlling the ui.root layout, you can control how other users experience your script.


Layouts control how widgets in a panel are arranged for display. There are two layout options, described below: flow layout and absolute layout. Layouts are specified with the ui.Panel.Layout class. Set a panel's layout either in the constructor or with setLayout(). The order in which widgets are added determines how widgets are arranged in a panel with flow layout. The position property each widget's style determines how a widget will be arranged in a panel with absolute layout. If the style on a widget is irrelevant for the layout in which the widget is placed, it's ignored.


A flow layout displays widgets in a row ('horizontal') or a column ('vertical'). The widgets are arranged according to the order in which they are added to the panel. For example, consider the following buttons added to a panel:

Code Editor (JavaScript)

// Create a panel with vertical flow layout.
var panel = ui.Panel({
  layout: ui.Panel.Layout.flow('vertical'),
  style: {width: '300px'}

// Add a bunch of buttons.
for (var i = 0; i < 30; i++) {
  panel.add(ui.Button({label: 'Button ' + i, style: {stretch: 'horizontal'}}));


The vertical layout should look something like:


Note that the width of the panel is set to 300 pixels and the stretch is set to 'horizontal' with the style property. The stretch style property applies to widgets in a panel with flow layout. For example, {stretch: 'horizontal'} means the widget will expand to fill available horizontal space within the panel. In the previous example, change the flow layout type to 'horizontal' to see the buttons arranged in a row instead of a column.

In a horizontal flow panel, a horizontally stretched widget expands to fill the space available after all other widgets have taken up their natural widths. If more than one widget is stretched horizontally, then the available horizontal space is split among them. A vertically stretched widget expands to fill the height of the panel.

In a vertical flow panel, a vertically stretched widget expands to fill the space available after all other widgets have taken up their natural heights. If more than one widget is stretched vertically, then the available vertical space is split among them. A horizontally stretched widget expands to fill the width of the panel.


An absolute layout positions widgets according to positions in the panel. Unlike the flow layout, the position of a widget is determined by the position property of the widget's style property, not the order in which it is added to the panel. The following example demonstrates using the root.ui panel with an absolute layout (the root panel's layout is a horizontal flow by default, but can be set with ui.root.setLayout()):

Code Editor (JavaScript)


// A function to make buttons labeled by position.
function makeButton(position) {
  return ui.Button({
    label: position,
    style: {position: position}

// Add labeled buttons to the panel.

The absolute layout panel should look something like:



When you add a widget to a panel, it adds the widget to the panel's list of widgets. Calling widgets() on the panel returns the which you can use to manipulate the widgets in the panel. Consider the following example, which adds widgets to a panel, adds the panel to the root panel, then updates a chart when the user clicks on the map:

Code Editor (JavaScript)

// Load and display NDVI data.
var ndvi = ee.ImageCollection('NOAA/VIIRS/001/VNP13A1')
    .filterDate('2021-01-01', '2022-01-01').select('NDVI');
  ndvi.median(), {min: 0, max: 10000, palette: ['99c199', '006400']}, 'NDVI');

// Configure the map.
Map.setCenter(-94.84497, 39.01918, 8);'cursor', 'crosshair');

// Create an empty panel in which to arrange widgets.
// The layout is vertical flow by default.
var panel = ui.Panel({style: {width: '400px'}})
    .add(ui.Label('Click on the map'));

// Set a callback function for when the user clicks the map.
Map.onClick(function(coords) {
  // Create or update the location label (the second widget in the panel)
  var location = 'lon: ' + coords.lon.toFixed(2) + ' ' +
                 'lat: ' +;
  panel.widgets().set(1, ui.Label(location));

  // Add a red dot to the map where the user clicked.
  var point = ee.Geometry.Point(coords.lon,;
  Map.layers().set(1, ui.Map.Layer(point, {color: 'FF0000'}));

  // Create a chart of NDVI over time.
  var chart = ui.Chart.image.series(ndvi, point, ee.Reducer.mean(), 200)
        title: 'NDVI Over Time',
        vAxis: {title: 'NDVI'},
        lineWidth: 1,
        pointSize: 3,

  // Add (or replace) the third widget in the panel by
  // manipulating the widgets list.
  panel.widgets().set(2, chart);

// Add the panel to the ui.root.

In this example, observe that first, widgets are added to panel using add(). In the callback function registered to map clicks, panel's list of widgets is modified instead. Specifically, the third widget (which may or may not exist) is set such that a new chart is displayed of NDVI over time. Learn more about event handling functions on the Events page.