Skip to main content
Containers are special Sprites that can hold child elements. They provide layout management, backgrounds, masking, and scrolling capabilities. Every chart, series, and composite element in amCharts 5 is built using Containers.

Creating a Container

import * as am5 from "@amcharts/amcharts5";

const root = am5.Root.new("chartdiv");

const container = root.container.children.push(
  am5.Container.new(root, {
    width: am5.percent(100),
    height: am5.percent(100),
    layout: root.verticalLayout
  })
);

Children Management

Containers maintain a children collection:
// Add children
const child1 = container.children.push(
  am5.Rectangle.new(root, {
    width: 100,
    height: 50,
    fill: am5.color(0xff0000)
  })
);

const child2 = container.children.push(
  am5.Circle.new(root, {
    radius: 30,
    fill: am5.color(0x00ff00)
  })
);

// Insert at specific position
container.children.insertIndex(0, am5.Rectangle.new(root, {}));

// Remove child
container.children.removeValue(child1);

// Clear all children
container.children.clear();

// Access children
const firstChild = container.children.getIndex(0);
const childCount = container.children.length;

Layouts

Containers support different layout strategies:

Vertical Layout

const container = am5.Container.new(root, {
  layout: root.verticalLayout,
  width: 300
});

// Children stack vertically
container.children.push(am5.Rectangle.new(root, {
  width: am5.percent(100),
  height: 50
}));

container.children.push(am5.Rectangle.new(root, {
  width: am5.percent(100),
  height: 50
}));

Horizontal Layout

const container = am5.Container.new(root, {
  layout: root.horizontalLayout,
  height: 100
});

// Children stack horizontally
container.children.push(am5.Rectangle.new(root, {
  width: 100,
  height: am5.percent(100)
}));

container.children.push(am5.Rectangle.new(root, {
  width: 100,
  height: am5.percent(100)
}));

Grid Layout

const container = am5.Container.new(root, {
  layout: root.gridLayout,
  width: 400,
  height: 300
});

// Children arrange in a grid
for (let i = 0; i < 9; i++) {
  container.children.push(am5.Rectangle.new(root, {
    width: 120,
    height: 90,
    fill: am5.color(0x0088ff)
  }));
}

No Layout

const container = am5.Container.new(root, {
  layout: null  // Manual positioning
});

// Position children manually
container.children.push(am5.Rectangle.new(root, {
  x: 10,
  y: 20,
  width: 100,
  height: 50
}));
When using layouts, child positioning is automatic. Manual x and y settings are ignored for children in layout-enabled containers.

Padding

Control internal spacing:
const container = am5.Container.new(root, {
  paddingLeft: 20,
  paddingRight: 20,
  paddingTop: 10,
  paddingBottom: 10,
  layout: root.verticalLayout
});

// Access inner dimensions
const innerWidth = container.innerWidth();
const innerHeight = container.innerHeight();

Backgrounds

Containers can have background elements:
const container = am5.Container.new(root, {
  width: 300,
  height: 200,
  background: am5.Rectangle.new(root, {
    fill: am5.color(0xeeeeee),
    fillOpacity: 0.8
  })
});

// Update background later
container.set("background", am5.RoundedRectangle.new(root, {
  fill: am5.color(0xff0000),
  cornerRadiusTL: 10,
  cornerRadiusTR: 10,
  cornerRadiusBL: 10,
  cornerRadiusBR: 10
}));

Masking

Content Masking

Clip content to container bounds:
const container = am5.Container.new(root, {
  width: 200,
  height: 150,
  maskContent: true  // Clips overflow
});

container.children.push(am5.Rectangle.new(root, {
  width: 300,  // Larger than container
  height: 200,
  fill: am5.color(0xff0000)
}));

Custom Mask

const container = am5.Container.new(root, {
  width: 200,
  height: 200,
  mask: am5.Circle.new(root, {
    radius: 100,
    centerX: am5.percent(50),
    centerY: am5.percent(50)
  })
});

Scrolling

Enable vertical scrolling:
const container = am5.Container.new(root, {
  width: 300,
  height: 200,
  layout: root.verticalLayout,
  verticalScrollbar: am5.Scrollbar.new(root, {
    orientation: "vertical"
  })
});

// Add content that exceeds container height
for (let i = 0; i < 20; i++) {
  container.children.push(am5.Rectangle.new(root, {
    width: am5.percent(100),
    height: 40,
    fill: am5.color(0x0088ff)
  }));
}

// Scroll to specific child
const targetChild = container.children.getIndex(10);
container.scrollToChild(targetChild);

Interactive Children

Control child interactivity:
const container = am5.Container.new(root, {
  interactiveChildren: true  // Enable interactions for all descendants
});

container.children.push(am5.Rectangle.new(root, {
  width: 100,
  height: 50,
  fill: am5.color(0xff0000)
})).events.on("click", () => {
  console.log("Rectangle clicked!");
});
Setting interactiveChildren: false can improve performance for containers with many non-interactive elements.

State Propagation

Apply states to children:
const container = am5.Container.new(root, {
  setStateOnChildren: true,
  interactive: true
});

// Create hover state for container
container.states.create("hover", {
  // Container hover state
});

// Add children - they'll receive hover state too
container.children.push(am5.Rectangle.new(root, {
  width: 100,
  height: 50,
  fill: am5.color(0x0088ff)
})).states.create("hover", {
  fill: am5.color(0x00aaff)
});

Reverse Children

Reverse the order of children in layout:
const container = am5.Container.new(root, {
  layout: root.horizontalLayout,
  reverseChildren: true  // Right to left
});

HTML Content

Embed HTML content in containers:
const container = am5.Container.new(root, {
  width: 300,
  height: 200,
  html: `
    <div style="padding: 20px;">
      <h3>HTML Content</h3>
      <p>This is HTML inside the container.</p>
    </div>
  `
});

// Update HTML dynamically
container.set("html", "<strong>Updated content</strong>");

Content Dimensions

Get actual content size:
const contentWidth = container.contentWidth();
const contentHeight = container.contentHeight();

console.log(`Content: ${contentWidth}x${contentHeight}`);

Walking Children

Iterate through all descendants:
// Recursively walk all children
container.walkChildren((child) => {
  console.log("Child:", child);
  
  if (child instanceof am5.Rectangle) {
    child.set("fill", am5.color(0xff0000));
  }
});

// Iterate direct children only
container.eachChildren((child) => {
  console.log("Direct child:", child);
});

Practical Examples

Card Layout

const card = am5.Container.new(root, {
  width: 300,
  layout: root.verticalLayout,
  paddingLeft: 20,
  paddingRight: 20,
  paddingTop: 15,
  paddingBottom: 15,
  background: am5.RoundedRectangle.new(root, {
    fill: am5.color(0xffffff),
    cornerRadiusTL: 8,
    cornerRadiusTR: 8,
    cornerRadiusBL: 8,
    cornerRadiusBR: 8,
    shadowColor: am5.color(0x000000),
    shadowBlur: 10,
    shadowOpacity: 0.2
  })
});

card.children.push(am5.Label.new(root, {
  text: "Card Title",
  fontSize: 20,
  fontWeight: "bold"
}));

card.children.push(am5.Label.new(root, {
  text: "Card content goes here...",
  fontSize: 14
}));

Header with Logo and Title

const header = am5.Container.new(root, {
  width: am5.percent(100),
  height: 60,
  layout: root.horizontalLayout,
  paddingLeft: 20,
  paddingRight: 20,
  background: am5.Rectangle.new(root, {
    fill: am5.color(0x2196f3)
  })
});

header.children.push(am5.Picture.new(root, {
  width: 40,
  height: 40,
  src: "logo.png"
}));

header.children.push(am5.Label.new(root, {
  text: "Dashboard",
  fontSize: 24,
  fill: am5.color(0xffffff),
  centerY: am5.percent(50),
  paddingLeft: 15
}));

Responsive Grid

const grid = am5.Container.new(root, {
  width: am5.percent(100),
  layout: root.gridLayout,
  paddingLeft: 10,
  paddingRight: 10,
  paddingTop: 10,
  paddingBottom: 10
});

// Add grid items
for (let i = 0; i < 12; i++) {
  const item = grid.children.push(am5.Container.new(root, {
    width: am5.percent(30),
    height: 150,
    marginLeft: 5,
    marginRight: 5,
    marginTop: 5,
    marginBottom: 5,
    background: am5.Rectangle.new(root, {
      fill: am5.color(0x0088ff)
    })
  }));
  
  item.children.push(am5.Label.new(root, {
    text: `Item ${i + 1}`,
    centerX: am5.percent(50),
    centerY: am5.percent(50),
    fill: am5.color(0xffffff)
  }));
}

Scrollable List

const list = am5.Container.new(root, {
  width: 300,
  height: 400,
  layout: root.verticalLayout,
  verticalScrollbar: am5.Scrollbar.new(root, {
    orientation: "vertical"
  }),
  background: am5.Rectangle.new(root, {
    fill: am5.color(0xf5f5f5)
  })
});

// Add list items
const items = [
  "Item 1", "Item 2", "Item 3", "Item 4", "Item 5",
  "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"
];

items.forEach((text) => {
  const item = list.children.push(am5.Container.new(root, {
    width: am5.percent(100),
    height: 50,
    paddingLeft: 15,
    interactive: true,
    background: am5.Rectangle.new(root, {
      fill: am5.color(0xffffff)
    })
  }));
  
  item.states.create("hover", {
    background: am5.Rectangle.new(root, {
      fill: am5.color(0xe3f2fd)
    })
  });
  
  item.children.push(am5.Label.new(root, {
    text: text,
    centerY: am5.percent(50)
  }));
});

Best Practices

  1. Choose the Right Layout: Use layouts for automatic positioning, null for manual control
  2. Use Padding Wisely: Padding affects layout calculation and can cause unexpected sizing
  3. Enable Masking When Needed: Only use maskContent when necessary for performance
  4. Dispose Properly: Containers automatically dispose children when disposed
  5. Avoid Deep Nesting: Keep container hierarchy as flat as possible
  6. Use Percent for Responsive: Prefer am5.percent() for widths and heights

Common Pitfalls

Layout vs Manual Positioning: Don’t mix layouts with manual x and y positioning. Choose one approach.
Performance: Containers with many children can impact performance. Consider virtualization for large lists.
Use interactiveChildren: false on containers with hundreds of non-interactive children to improve performance.