diff --git a/BlazingDev.BlazorToolkit/Components/BzObjectInspector.razor b/BlazingDev.BlazorToolkit/Components/BzObjectInspector.razor
new file mode 100644
index 0000000..9dbd522
--- /dev/null
+++ b/BlazingDev.BlazorToolkit/Components/BzObjectInspector.razor
@@ -0,0 +1,59 @@
+@page "/BzObjectInspector"
+@using System.Reflection
+
+
+ @RenderObjectTree(ObjectToInspect)
+
+
+@code {
+ [Parameter] public object ObjectToInspect { get; set; }
+
+ private RenderFragment RenderObjectTree(object obj) => builder =>
+ {
+ var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ foreach (var property in properties)
+ {
+ var value = property.GetValue(obj);
+ var isExpandable = value != null && !value.GetType().IsPrimitive && value.GetType() != typeof(string);
+
+ builder.OpenElement(0, "div");
+ builder.AddAttribute(1, "class", "bz-object-inspector-node");
+
+ if (isExpandable)
+ {
+ builder.OpenElement(2, "button");
+ builder.AddAttribute(3, "onclick", EventCallback.Factory.Create(this, () => ToggleExpandCollapse(property.Name)));
+ builder.AddContent(4, IsExpanded(property.Name) ? "-" : "+");
+ builder.CloseElement();
+ }
+
+ builder.AddContent(5, $"{property.Name}: {value}");
+
+ if (isExpandable && IsExpanded(property.Name))
+ {
+ builder.OpenElement(6, "div");
+ builder.AddAttribute(7, "class", "bz-object-inspector-children");
+ builder.AddContent(8, RenderObjectTree(value));
+ builder.CloseElement();
+ }
+
+ builder.CloseElement();
+ }
+ };
+
+ private HashSet expandedNodes = new();
+
+ private void ToggleExpandCollapse(string nodeName)
+ {
+ if (expandedNodes.Contains(nodeName))
+ {
+ expandedNodes.Remove(nodeName);
+ }
+ else
+ {
+ expandedNodes.Add(nodeName);
+ }
+ }
+
+ private bool IsExpanded(string nodeName) => expandedNodes.Contains(nodeName);
+}
diff --git a/BlazingDev.BlazorToolkit/Components/BzObjectInspector.razor.cs b/BlazingDev.BlazorToolkit/Components/BzObjectInspector.razor.cs
new file mode 100644
index 0000000..336c520
--- /dev/null
+++ b/BlazingDev.BlazorToolkit/Components/BzObjectInspector.razor.cs
@@ -0,0 +1,58 @@
+using Microsoft.AspNetCore.Components;
+using System.Reflection;
+
+namespace BlazingDev.BlazorToolkit.Components;
+
+public partial class BzObjectInspector : ComponentBase
+{
+ [Parameter] public object ObjectToInspect { get; set; }
+
+ private HashSet expandedNodes = new();
+
+ private RenderFragment RenderObjectTree(object obj) => builder =>
+ {
+ var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ foreach (var property in properties)
+ {
+ var value = property.GetValue(obj);
+ var isExpandable = value != null && !value.GetType().IsPrimitive && value.GetType() != typeof(string);
+
+ builder.OpenElement(0, "div");
+ builder.AddAttribute(1, "class", "bz-object-inspector-node");
+
+ if (isExpandable)
+ {
+ builder.OpenElement(2, "button");
+ builder.AddAttribute(3, "onclick", EventCallback.Factory.Create(this, () => ToggleExpandCollapse(property.Name)));
+ builder.AddContent(4, IsExpanded(property.Name) ? "-" : "+");
+ builder.CloseElement();
+ }
+
+ builder.AddContent(5, $"{property.Name}: {value}");
+
+ if (isExpandable && IsExpanded(property.Name))
+ {
+ builder.OpenElement(6, "div");
+ builder.AddAttribute(7, "class", "bz-object-inspector-children");
+ builder.AddContent(8, RenderObjectTree(value));
+ builder.CloseElement();
+ }
+
+ builder.CloseElement();
+ }
+ };
+
+ private void ToggleExpandCollapse(string nodeName)
+ {
+ if (expandedNodes.Contains(nodeName))
+ {
+ expandedNodes.Remove(nodeName);
+ }
+ else
+ {
+ expandedNodes.Add(nodeName);
+ }
+ }
+
+ private bool IsExpanded(string nodeName) => expandedNodes.Contains(nodeName);
+}
diff --git a/Playground/AppFrame/NavMenu.razor b/Playground/AppFrame/NavMenu.razor
index 520459e..68b89ee 100644
--- a/Playground/AppFrame/NavMenu.razor
+++ b/Playground/AppFrame/NavMenu.razor
@@ -19,5 +19,11 @@
BzTimerComponents
+
+
+
+ BzObjectInspector
+
+
diff --git a/Playground/Components/BzObjectInspectorUsage.razor b/Playground/Components/BzObjectInspectorUsage.razor
new file mode 100644
index 0000000..b41735c
--- /dev/null
+++ b/Playground/Components/BzObjectInspectorUsage.razor
@@ -0,0 +1,37 @@
+@page "/BzObjectInspectorUsage"
+@using BlazingDev.BlazorToolkit.Components
+
+
+ Object Inspector Usage
+
+
+
+@code {
+ private SampleObject sampleObject = new SampleObject
+ {
+ Name = "Sample Object",
+ Age = 30,
+ Address = new Address
+ {
+ Street = "123 Main St",
+ City = "Anytown",
+ State = "CA",
+ ZipCode = "12345"
+ }
+ };
+
+ private class SampleObject
+ {
+ public string Name { get; set; }
+ public int Age { get; set; }
+ public Address Address { get; set; }
+ }
+
+ private class Address
+ {
+ public string Street { get; set; }
+ public string City { get; set; }
+ public string State { get; set; }
+ public string ZipCode { get; set; }
+ }
+}
diff --git a/Playground/Pages/BzObjectInspectorPage.razor b/Playground/Pages/BzObjectInspectorPage.razor
new file mode 100644
index 0000000..3ff7fef
--- /dev/null
+++ b/Playground/Pages/BzObjectInspectorPage.razor
@@ -0,0 +1,9 @@
+@page "/BzObjectInspector"
+
+BzObjectInspector
+
+BzObjectInspector
+
+This page showcases the BzObjectInspector component in the Playground app.
+
+