diff --git a/packages/core/components/LayerTree/index.tsx b/packages/core/components/LayerTree/index.tsx
new file mode 100644
index 000000000..2c6181c4e
--- /dev/null
+++ b/packages/core/components/LayerTree/index.tsx
@@ -0,0 +1,144 @@
+import styles from "./styles.module.css";
+import getClassNameFactory from "../../lib/get-class-name-factory";
+import { Data } from "../../types/Config";
+import { ItemSelector } from "../../lib/get-item";
+import { scrollIntoView } from "../../lib/scroll-into-view";
+import { ChevronDown, Grid, Layers, Type } from "react-feather";
+import { rootDroppableId } from "../../lib/root-droppable-id";
+import { useContext } from "react";
+import { dropZoneContext } from "../DropZone/context";
+import { findDropzonesForArea } from "../../lib/find-dropzones-for-area";
+
+const getClassName = getClassNameFactory("LayerTree", styles);
+const getClassNameLayer = getClassNameFactory("Layer", styles);
+
+export const LayerTree = ({
+ data,
+ dropzoneContent,
+ itemSelector,
+ setItemSelector,
+ dropzone,
+ label,
+}: {
+ data: Data;
+ dropzoneContent: Data["content"];
+ itemSelector: ItemSelector | null;
+ setItemSelector: (item: ItemSelector | null) => void;
+ dropzone?: string;
+ label?: string;
+}) => {
+ const dropzones = data.dropzones || {};
+
+ const ctx = useContext(dropZoneContext);
+
+ return (
+ <>
+ {label && (
+
+ )}
+
+ {dropzoneContent.length === 0 && (
+ No items
+ )}
+ {dropzoneContent.map((item, i) => {
+ const isSelected =
+ itemSelector?.index === i &&
+ (itemSelector.dropzone === dropzone ||
+ (itemSelector.dropzone === rootDroppableId && !dropzone));
+
+ const dropzonesForItem = findDropzonesForArea(data, item.props.id);
+ const containsDropzone = Object.keys(dropzonesForItem).length > 0;
+
+ const isHovering = ctx?.hoveringComponent === item.props.id;
+
+ const {
+ setHoveringArea = () => {},
+ setHoveringComponent = () => {},
+ } = ctx || {};
+
+ return (
+ -
+
+
{
+ if (isSelected) {
+ setItemSelector(null);
+ return;
+ }
+
+ setItemSelector({
+ index: i,
+ dropzone,
+ });
+
+ const id = dropzoneContent[i].props.id;
+
+ scrollIntoView(
+ document.querySelector(
+ `[data-rbd-drag-handle-draggable-id="draggable-${id}"]`
+ ) as HTMLElement
+ );
+ }}
+ onMouseOver={(e) => {
+ e.stopPropagation();
+ setHoveringArea(item.props.id);
+ setHoveringComponent(item.props.id);
+ }}
+ onMouseOut={(e) => {
+ e.stopPropagation();
+ setHoveringArea(null);
+ setHoveringComponent(null);
+ }}
+ >
+ {containsDropzone && (
+
+
+
+ )}
+
+
+ {item.type === "Text" || item.type === "Heading" ? (
+
+ ) : (
+
+ )}
+
+ {item.type}
+
+
+
+ {containsDropzone &&
+ Object.keys(dropzonesForItem).map((dropzoneKey, idx) => (
+
+
+
+ ))}
+
+ );
+ })}
+
+ >
+ );
+};
diff --git a/packages/core/components/LayerTree/styles.module.css b/packages/core/components/LayerTree/styles.module.css
new file mode 100644
index 000000000..3e570dab4
--- /dev/null
+++ b/packages/core/components/LayerTree/styles.module.css
@@ -0,0 +1,102 @@
+.LayerTree {
+ color: var(--puck-color-grey-2);
+ font-family: var(--puck-font-stack);
+ font-size: var(--puck-font-size-xxs);
+ margin: 0;
+ position: relative;
+ list-style: none;
+ padding: 0;
+}
+
+.LayerTree-dropzoneTitle {
+ color: var(--puck-color-grey-4);
+ font-size: var(--puck-font-size-xxxs);
+ text-transform: uppercase;
+}
+
+.LayerTree-helper {
+ text-align: center;
+ color: var(--puck-color-grey-6);
+ font-family: var(--puck-font-stack);
+}
+
+.Layer {
+ position: relative;
+ border: 1px solid transparent;
+}
+
+.Layer-inner {
+ padding-left: 20px;
+ padding-right: 8px;
+ border-radius: 3px;
+}
+
+.Layer--containsDropzone > .Layer-inner {
+ padding-left: 8px;
+}
+
+.Layer-clickable {
+ align-items: center;
+ display: flex;
+}
+
+.Layer-inner:hover {
+ cursor: pointer;
+}
+
+.Layer:not(.Layer--isSelected) > .Layer-inner:hover,
+.Layer--isHovering > .Layer-inner {
+ color: var(--puck-color-blue);
+ background: var(--puck-color-azure-85);
+}
+
+.Layer--isSelected {
+ background: var(--puck-color-azure-9);
+ border-color: var(--puck-color-azure-7);
+ border-radius: 4px;
+}
+
+.Layer--isSelected > .Layer-inner {
+ background: var(--puck-color-azure-85);
+ font-weight: 600;
+}
+
+.Layer--isSelected > .Layer-inner > .Layer-clickable > .Layer-chevron,
+.Layer:has(.Layer--isSelected)
+ > .Layer-inner
+ > .Layer-clickable
+ > .Layer-chevron {
+ transform: scaleY(-1);
+}
+
+.Layer-dropzones {
+ display: none;
+ margin-left: 20px;
+}
+
+.Layer--isSelected > .Layer-dropzones,
+.Layer:has(.Layer--isSelected) > .Layer-dropzones {
+ display: block;
+}
+
+.Layer-dropzones > .LayerTree {
+ margin-left: 16px;
+}
+
+.Layer-title,
+.LayerTree-dropzoneTitle {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ margin: 8px 4px;
+}
+
+.Layer-icon {
+ color: var(--puck-color-rose-6);
+ margin-top: 4px;
+}
+
+.Layer-dropzoneIcon {
+ color: var(--puck-color-grey-7);
+ margin-top: 4px;
+}