+ @if (!headingHidden() || (subtitleText() && !subtitleHidden())) {
+
+ }
+
+
+
+
+
+
+
+ @if (showLegend()) {
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/components/charts/src/lib/modules/chart/chart.component.scss b/libs/components/charts/src/lib/modules/chart/chart.component.scss
new file mode 100644
index 0000000000..c174d23ba6
--- /dev/null
+++ b/libs/components/charts/src/lib/modules/chart/chart.component.scss
@@ -0,0 +1,49 @@
+@use 'libs/components/theme/src/lib/styles/compat-tokens-mixins' as compatMixins;
+
+@include compatMixins.sky-default-overrides('.sky-chart') {
+ // TODO: Add overrides here
+}
+
+.sky-chart {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ column-gap: var(--sky-space-gap-text_action-m, 12px);
+}
+
+.sky-chart-header {
+ grid-column: 1;
+}
+
+.sky-chart-heading {
+ h2,
+ h3,
+ h4,
+ h5 {
+ display: inline;
+ margin-block: 0;
+ }
+}
+
+.sky-chart-subtitle {
+ grid-column: 1;
+ font-family: var(--sky-font-family-primary);
+ font-size: var(--sky-font-size-body-m);
+ font-weight: var(--sky-font-style-body-m);
+ line-height: var(--sky-font-line_height-body-m);
+ color: var(--sky-color-text-deemphasized);
+}
+
+.sky-chart-content {
+ grid-column: 1 / -1;
+ margin: 0;
+}
+
+sky-chart-legend {
+ grid-column: 1 / -1;
+}
+
+.sky-chart-actions {
+ grid-column: 2;
+ grid-row: 1;
+ align-self: start;
+}
diff --git a/libs/components/charts/src/lib/modules/chart/chart.component.ts b/libs/components/charts/src/lib/modules/chart/chart.component.ts
new file mode 100644
index 0000000000..65a6bbf2e4
--- /dev/null
+++ b/libs/components/charts/src/lib/modules/chart/chart.component.ts
@@ -0,0 +1,152 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ TemplateRef,
+ booleanAttribute,
+ computed,
+ effect,
+ inject,
+ input,
+} from '@angular/core';
+import { SkyHelpInlineModule } from '@skyux/help-inline';
+import { SkyModalService } from '@skyux/modals';
+import { SkyDropdownModule } from '@skyux/popovers';
+
+import { SkyChartGridModalContext } from '../chart-data-grid-modal/chart-data-grid-modal-context';
+import { SkyChartDataGridModalComponent } from '../chart-data-grid-modal/chart-data-grid-modal.component';
+import { SkyChartLegendItem } from '../chart-legend/chart-legend-item';
+import { SkyChartLegendComponent } from '../chart-legend/chart-legend.component';
+import { SkyChartsResourcesModule } from '../shared/sky-charts-resources.module';
+import {
+ DefaultHeadingLevel,
+ SkyChartHeadingLevel,
+ headingLevelInputTransformer,
+} from '../shared/types/chart-heading-level';
+import {
+ DefaultHeadingStyle,
+ SkyChartHeadingStyle,
+ headingStyleInputTransformer,
+} from '../shared/types/chart-heading-style';
+
+import { SkyChartService } from './chart.service';
+
+/**
+ * Wrapper component that provides heading and subtitle context to nested chart components.
+ * Use this as the outer container and place a chart type component (e.g. `sky-chart-bar`) inside it.
+ */
+@Component({
+ selector: 'sky-chart',
+ templateUrl: 'chart.component.html',
+ styleUrl: 'chart.component.scss',
+ imports: [
+ SkyChartsResourcesModule,
+ SkyDropdownModule,
+ SkyHelpInlineModule,
+ SkyChartLegendComponent,
+ ],
+ providers: [SkyChartService],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SkyChartComponent {
+ // #region Dependency Injection
+ readonly #modalService = inject(SkyModalService);
+ readonly #chartService = inject(SkyChartService);
+ // #endregion
+
+ // #region Inputs
+
+ /**
+ * The text to display as the chart's heading.
+ */
+ public readonly headingText = input.required