diff --git a/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor b/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor
new file mode 100644
index 0000000..b1c4d9a
--- /dev/null
+++ b/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor
@@ -0,0 +1,36 @@
+@typeparam TItem
+
+
+ @if (ShowFilterPanel && FilterPanel is not null)
+ {
+
+ @FilterPanel
+
+ }
+
+ @if (Data is { Count: > 0 })
+ {
+
+
+ @if (ShowPager && Data.Count > PageSize)
+ {
+
+ }
+ }
+
diff --git a/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor.cs b/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor.cs
new file mode 100644
index 0000000..e3e9133
--- /dev/null
+++ b/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor.cs
@@ -0,0 +1,163 @@
+using Microsoft.AspNetCore.Components;
+using Microsoft.JSInterop;
+
+namespace AyCode.Blazor.Components.Components.CardViews;
+
+///
+/// Generic card view component that displays items in a responsive CSS Grid layout
+/// with optional pagination and scroll-to-item support.
+///
+/// The type of data item displayed in each card.
+public partial class MgCardView : ComponentBase
+{
+ [Inject] private IJSRuntime JSRuntime { get; set; } = null!;
+
+ ///
+ /// The collection of items to display as cards.
+ ///
+ [Parameter, EditorRequired]
+ public IReadOnlyList Data { get; set; } = [];
+
+ ///
+ /// Template for rendering each card's content.
+ ///
+ [Parameter, EditorRequired]
+ public RenderFragment CardTemplate { get; set; } = null!;
+
+ ///
+ /// Fired when a card is clicked/tapped.
+ ///
+ [Parameter]
+ public EventCallback OnCardClick { get; set; }
+
+ ///
+ /// Number of columns on extra-small screens (below 576px). Default: 1.
+ ///
+ [Parameter]
+ public int ColumnCountXs { get; set; } = 1;
+
+ ///
+ /// Number of columns on small screens (576–768px). Default: 2.
+ ///
+ [Parameter]
+ public int ColumnCountSm { get; set; } = 2;
+
+ ///
+ /// Number of columns on medium+ screens (769px+). Default: 3.
+ ///
+ [Parameter]
+ public int ColumnCountLg { get; set; } = 3;
+
+ ///
+ /// Whether to show the pager below the cards. Default: false.
+ ///
+ [Parameter]
+ public bool ShowPager { get; set; }
+
+ ///
+ /// Number of items per page when paging is enabled. Default: 12.
+ ///
+ [Parameter]
+ public int PageSize { get; set; } = 12;
+
+ ///
+ /// Additional CSS class for the card view container.
+ ///
+ [Parameter]
+ public string? CssClass { get; set; }
+
+ ///
+ /// Additional CSS class applied to each individual card wrapper.
+ ///
+ [Parameter]
+ public string? CardCssClass { get; set; }
+
+ ///
+ /// Height of the card view container (e.g., "500px", "70vh"). When set, the component uses its own scroll area.
+ ///
+ [Parameter]
+ public string? Height { get; set; }
+
+ ///
+ /// Whether to show the filter panel above the cards. Default: false.
+ ///
+ [Parameter]
+ public bool ShowFilterPanel { get; set; }
+
+ ///
+ /// Custom content for the filter panel. Rendered above the card grid when ShowFilterPanel is true.
+ ///
+ [Parameter]
+ public RenderFragment? FilterPanel { get; set; }
+
+ ///
+ /// Item to scroll into view after render. Set to null to disable.
+ ///
+ [Parameter]
+ public TItem? ScrollToItem { get; set; }
+
+ ///
+ /// Key selector for identifying items (e.g., item => item.Id). Required when ScrollToItem is used.
+ ///
+ [Parameter]
+ public Func? ItemKeySelector { get; set; }
+
+ private int _activePageIndex;
+ private object? _lastScrolledKey;
+
+ private string? ContainerStyle => Height is not null ? $"height: {Height};" : null;
+
+ private IReadOnlyList PagedItems
+ {
+ get
+ {
+ if (!ShowPager)
+ return Data;
+
+ return Data
+ .Skip(_activePageIndex * PageSize)
+ .Take(PageSize)
+ .ToList();
+ }
+ }
+
+ private async Task OnCardClickInternal(TItem item)
+ {
+ if (OnCardClick.HasDelegate)
+ await OnCardClick.InvokeAsync(item);
+ }
+
+ private void OnActivePageIndexChanged(int newPageIndex)
+ {
+ _activePageIndex = newPageIndex;
+ }
+
+ ///
+ /// Generates a stable DOM element id for a card item using the key selector.
+ ///
+ private string? GetCardElementId(TItem item)
+ {
+ return ItemKeySelector is null ? null : $"mg-card-{ItemKeySelector(item)}";
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (ScrollToItem is not null && ItemKeySelector is not null)
+ {
+ var key = ItemKeySelector(ScrollToItem);
+ if (!Equals(key, _lastScrolledKey))
+ {
+ _lastScrolledKey = key;
+ var elementId = $"mg-card-{key}";
+ try
+ {
+ await JSRuntime.InvokeVoidAsync("MgCardView.scrollToElement", elementId);
+ }
+ catch (JSException)
+ {
+ // JS might not be loaded yet
+ }
+ }
+ }
+ }
+}
diff --git a/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor.css b/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor.css
new file mode 100644
index 0000000..048e9cb
--- /dev/null
+++ b/AyCode.Blazor.Components/Components/CardViews/MgCardView.razor.css
@@ -0,0 +1,52 @@
+.mg-card-view-container {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.mg-card-scroll-area {
+ flex: 1;
+ overflow-y: auto;
+ padding-right: 4px;
+}
+
+.mg-card-grid {
+ display: grid;
+ gap: 1rem;
+ grid-template-columns: repeat(var(--cols-xs, 1), 1fr);
+}
+
+@media (min-width: 576px) {
+ .mg-card-grid {
+ grid-template-columns: repeat(var(--cols-sm, 2), 1fr);
+ }
+}
+
+@media (min-width: 769px) {
+ .mg-card-grid {
+ grid-template-columns: repeat(var(--cols-lg, 3), 1fr);
+ }
+}
+
+.mg-card {
+ border: 1px solid #dee2e6;
+ border-radius: 8px;
+ padding: 16px;
+ background-color: #fff;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+ transition: box-shadow 0.2s ease, transform 0.15s ease;
+ height: 100%;
+}
+
+.mg-card:hover {
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-2px);
+}
+
+.mg-card-filter-panel {
+ margin-bottom: 12px;
+ padding: 12px 16px;
+ background-color: #f8f9fa;
+ border: 1px solid #dee2e6;
+ border-radius: 8px;
+}
diff --git a/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs b/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs
index 93b0746..630b6f2 100644
--- a/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs
+++ b/AyCode.Blazor.Components/Components/Grids/MgGridDataColumn.cs
@@ -1,6 +1,8 @@
using DevExpress.Blazor;
using Microsoft.AspNetCore.Components;
-using Microsoft.AspNetCore.Components.Rendering;
+using System.Collections.Concurrent;
+using System.Linq.Expressions;
+using System.Text;
using System.Text.RegularExpressions;
namespace AyCode.Blazor.Components.Components.Grids;
@@ -8,10 +10,13 @@ namespace AyCode.Blazor.Components.Components.Grids;
///
/// Extended DxGridDataColumn with additional parameters for InfoPanel support.
///
-public class MgGridDataColumn : DxGridDataColumn
+public partial class MgGridDataColumn : DxGridDataColumn
{
+ private static readonly ConcurrentDictionary<(Type Type, string Property), Func