@microsoft/fabric-visuals-core
v4.1.0
Published
Core library for Fabric Apps - Analytics — data utilities, design tokens, and configuration
Readme
@microsoft/fabric-visuals-core
The fabric-visuals-core package is a foundational component of the "Fabric visualization components" ecosystem. It defines the common contracts and helpers, such as foundational shared types, data utilities, format helpers, localization scaffolding, and design tokens for sibling components:
@microsoft/fabric-visuals— data visualization component built on those shared contracts@microsoft/fabric-datagrid— grid/table component built on the same data and formatting model
Quick Reference
- Package:
@microsoft/fabric-visuals-core- Purpose: Shared types, data utilities, localization, format helpers, and design tokens for the Fabric Apps visualization stack.
- Use when: You need
DataTable,ColumnDef, component localization, design tokens, data filtering/aggregation, or VBA format conversion. This is a required dependency for both@microsoft/fabric-visualsand@microsoft/fabric-datagrid.- Do NOT use when: You want to render charts (use
@microsoft/fabric-visuals) or data grids (use@microsoft/fabric-datagrid) — those packages re-export what they need.- Key exports:
DataTable,ColumnDef,VisualTheme,VisualFramingProps,VisualContainerCapabilities,HeaderProps,loadStrings,getString,formatString,filterRows,aggregate,groupBy,convertVbaFormat,formatValue,tokens,spacing,injectDesignTokens,VISUALS_COMPONENT_LAYER,VISUALS_TOKENS_LAYER- Peer dependencies: None
- Install:
npm install @microsoft/fabric-visuals-core
Table of Contents
- Installation
- Data
- Localization
- Design Tokens and Theming
- Visual framing contracts
- Examples
- Trademarks
- Security
- Code of conduct
Installation
Install via npm:
npm install @microsoft/fabric-visuals-coreData
To support the consistent sharing of dense, two-dimensional data to our components, we define a DataTable type that conveys this table of data, along with metadata corresponding to the columns of the associated data table. This metadata helps components render with the appropriate UX-facing display name, formats data values according to a format string, associates data with a semantic type, and sets a default aggregation for displaying totals.
export interface ColumnDef {
readonly name: string;
readonly displayName?: string;
readonly format?: string;
readonly semanticType?: SemanticType;
readonly defaultAggregation?: AggregationFn;
}
export interface DataTable {
readonly columns: ColumnDef[];
readonly rows: unknown[][];
}The name is expected to be the referent for when components need to address a specific column. The data structure makes no guarantees that this name is unique among all columns, and callers should ensure that this name is unique to resist undefined behavior.
The displayName is expected to be used when displaying the name of the column, such as in axis titles or column headers.
The column's format is given in ECMA-376 format, a Microsoft documentation page is available. It is expected that wherever a data value is presented to a user that this format string is used to format the number (e.g., data label on a chart, cell value in a table).
semanticType explicitly inherits from Flint's semantic type system. It is expected that this semantic type is evaluated by an AI agent based on a sample of data and the column metadata; see Flint's authoring skill under the "Semantic types" heading an example. This property is only required when providing a Flint specification to the fabric-visuals data visualization component.
defaultAggregation sets the default aggregation when displaying a client-side-computed column total. This is used in the fabric-datagrid table component when showing a totals row.
The data itself is explicitly untyped by unknown. It is up to the consuming component to derive appropriate semantics from the provided data and column metadata.
Utilities, aggregation, filtering, and grouping
We provide some data utilities to do client-side operations on datasets stored in a DataTable format. If your data originates as Apache Arrow or other binary format, we recommend doing operations in that format instead (or pushing such data operations to the data provider backend), for performance reasons.
export function convertDataTableToRows(input: DataTable): Record<string, unknown>[]
export function isDataTable(input: unknown): input is DataTableFiltering
export function filterRows(
table: DataTable,
predicate: (row: unknown[], columns: readonly ColumnDef[]) => boolean,
): DataTableGiven a predicate, return a filtered DataTable containing rows for which the predicate evaluated to truthy.
export function getUniqueColumnValues(table: DataTable, columnName: string): unknown[]Using JavaScript strict-equals semantics, return unique values for a specific column.
export function sliceRows(table: DataTable, start: number, end?: number): DataTableUsing the same semantics as Array.slice(), return a 0-indexed subset of the provided DataTable rows.
Aggregation / Group By
export type AggregationFn = 'sum' | 'min' | 'max' | 'average' | 'count'
export interface AggregationSpec {
readonly column?: string;
readonly fn: AggregationFn;
readonly as?: string;
}
export function aggregate(table: DataTable, spec: AggregationSpec): number | undefinedGiven an aggregation specification, aggregate the specified column name by the targeted operation, returning a numerical aggregation. For operations other than "count", aggregated non-numeric data will evaluate to undefined.
export function aggregateMany(
table: DataTable,
specs: readonly AggregationSpec[],
): Record<string, number | undefined>
export function aggregateByName(
rows: readonly Record<string, unknown>[],
spec: AggregationSpec,
): number | undefined
export function aggregateManyByName(
rows: readonly Record<string, unknown>[],
columns: readonly ColumnDef[],
specs: readonly AggregationSpec[],
): Record<string, number | undefined>The *ByName variants take object-keyed rows (Record<string, unknown>[]) instead of a DataTable. These functions are used by fabric-datagrid grand totals, whose rows are already keyed by column.
export function groupBy(
table: DataTable,
groupColumns: string[],
aggregations: AggregationSpec[],
): DataTableGiven an aggregation specification, aggregate the specified column name by the targeted operation, removing the named column and replacing it with the AggregationSpec.as column name. If as is not specified, the template <fn>_<name> will be used for the new column. The generated column will inherit the other column metadata from the original column (displayName will match the generated name).
Columns not named by the aggregations are assumed to be the "group by" columns, so unique combinatorial sets of those columns will determine the aggregation scope.
Formatting data
To support components formatting data, we provide a convenience method based on the numfmt package. This method takes a given (numerical) value and formats it based on the given format string.
export function formatValue(
value: unknown,
vbaFormat: string | undefined,
options?: { locale?: string, compact?: boolean },
): unknownIf the value is null or undefined, no formatting is attempted and the value is returned verbatim. Similarly, if no vbaFormat is provided, the value is returned verbatim.
locale affects the interpretation of number grouping and decimal punctuation. If not provided, try to recover the currently-set formatting locale via getFormattingLocale() (see below), or default to "en-US".
compact will attempt to use display units to generalize and shorten the number display. Under the hood, this uses the Intl.NumberFormat formatter, setting notation to 'compact', compactDisplay to 'short', and maximumFractionDigits to the max of the number of max fraction digits of the format string or 1, while also supplying the given locale as above. The compacted number is rehydrated with static textual elements from the format string.
For example, formatValue(100000, '$0.#', { compact: true }) will return "$100K".
Localization
Centralizes localization functionality for use by child components. We (will) provide localization for all our components in all languages supported by Microsoft Fabric (see docs).
Built-in component strings are English (en-US) by default. Load another locale before rendering components to display translated labels and messages:
import {
loadStrings,
type AvailableLocale,
} from '@microsoft/fabric-visuals-core';
async function setLanguage(locale: AvailableLocale) {
await loadStrings(locale);
renderApplication();
}Only the requested locale is loaded. Call loadStrings() again and re-render
the application to switch languages. Missing translated values fall back to
the default en-US strings.
For environments that cannot use dynamic imports, activate a statically imported locale:
import { setStrings } from '@microsoft/fabric-visuals-core';
import { strings } from '@microsoft/fabric-visuals-core/localization/locales/en';
setStrings('en', strings);Use availableLocales to inspect the locales included in the installed package
and getLoadedLocale() to read the active locale. getString() performs a
type-safe lookup, while formatString() replaces positional ({0}) or named
({count}) placeholders.
Design Tokens and Theming
We define some static design tokens to standardize the design language around component formatting. This formatting includes spacing, typography, semantic colors, data colors, radii, and borders.
export const spacing: {
readonly none: '0';
readonly xxs: '2px';
readonly xs: '4px';
readonly sNudge: '6px';
readonly s: '8px';
readonly mNudge: '10px';
readonly m: '12px';
readonly l: '16px';
readonly xl: '20px';
readonly xxl: '24px';
readonly xxxl: '32px';
}
export const fontSize: {
readonly 100: '10px';
readonly 200: '12px';
readonly 300: '14px';
readonly 400: '16px';
readonly 500: '20px';
readonly 600: '24px';
readonly hero700: '28px';
readonly hero800: '32px';
readonly hero900: '40px';
readonly hero1000: '68px';
}
export const lineHeight: {
readonly 100: '14px';
readonly 200: '16px';
readonly 300: '20px';
readonly 400: '22px';
readonly 500: '28px';
readonly 600: '32px';
readonly hero700: '36px';
readonly hero800: '40px';
readonly hero900: '52px';
readonly hero1000: '92px';
}
export const fontWeight: {
readonly regular: 400;
readonly medium: 500;
readonly semibold: 600;
readonly bold: 700;
}
export const fontFamily: {
readonly heading: "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif";
readonly base: "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif";
readonly monospace: "Consolas, 'Courier New', Courier, monospace";
readonly numeric: "Bahnschrift, 'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif";
}
export const iconSize: {
readonly 100: '12px';
readonly 200: '16px';
readonly 300: '20px';
readonly 400: '24px';
readonly 500: '28px';
readonly 600: '32px';
readonly 700: '48px';
}
export const borderRadius: {
readonly none: '0';
readonly small: '2px';
readonly medium: '4px';
readonly large: '6px';
readonly xLarge: '8px';
readonly '2xl': '12px';
readonly '3xl': '16px';
readonly '4xl': '24px';
readonly '5xl': '32px';
readonly '6xl': '40px';
readonly circular: '9999px';
}
export function injectDesignTokens(): booleanCascade layers
The visualization packages emit their CSS into two namespaced CSS @layers:
export const VISUALS_TOKENS_LAYER = 'fabric-visual-tokens'
export const VISUALS_COMPONENT_LAYER = 'fabric-visuals'injectDesignTokens() places the default :root custom properties in
fabric-visual-tokens. Griffel and static component rules from the visual,
visual-container, and data-grid packages use fabric-visuals.
Because fabric-visual-tokens is declared before fabric-visuals, a
host-specific layer-order declaration is not strictly needed when host
overrides are unlayered. Normal unlayered author declarations targeting a
visual or visual container naturally have higher priority than normal
declarations in named layers (see MDN's
Normal author declarations).
Hosts whose overrides use named cascade layers must still declare where the
Fabric layers belong before any of those layer names first appear.
export interface VisualTheme {
foreground: string;
foregroundSecondary: string;
brandForeground: string;
brandBackground: string;
categoricalPalette?: readonly string[];
background: string;
backgroundSecondary: string;
backgroundHover: string;
stroke: string;
typography?: {
heading?: { family?: string; size?: number; weight?: number; style?: string };
label?: { family?: string; size?: number; weight?: number; style?: string };
dataLabel?: { family?: string };
};
spacing?: {
cellPadding?: string;
};
border?: {
width?: number;
radius?: string;
};
}
export function readCssTheme(element?: Element): VisualThemeWe provide a default implementation of VisualTheme that roughly matches Power BI and FLuent 2 UI guidelines (see exported consts below). It is also possible to etch CSS variables into the document, then recall those settings into a VisualTheme object by using the function readCssTheme().
readCssTheme() builds categoricalPalette from a contiguous sequence of
--color-data-1 through --color-data-10. If --color-data-1 is unset, the
field remains undefined so chart packages can use their built-in palette.
The values come from computed styles, so the same properties can be overridden
inside the host's .dark rule to provide a dark-mode palette.
CSS_CATEGORY_PALETTE_VARS exports the ordered custom-property names for tools
that need to enumerate the supported slots.
export const CSS_VAR_BY_THEME_KEY: {
readonly foreground: '--color-foreground';
readonly background: '--color-card';
readonly stroke: '--color-border';
readonly foregroundSecondary: '--color-muted-foreground';
readonly backgroundSecondary: '--color-muted';
readonly backgroundHover: '--color-hover';
readonly brandBackground: '--color-brand';
readonly brandForeground: '--color-brand-foreground';
}
export const CSS_CATEGORY_PALETTE_VARS = [
'--color-data-1',
'--color-data-2',
'--color-data-3',
'--color-data-4',
'--color-data-5',
'--color-data-6',
'--color-data-7',
'--color-data-8',
'--color-data-9',
'--color-data-10',
]
export function cssThemeChanged(a: VisualTheme, b: VisualTheme): boolean
export const lightThemeColors: VisualTheme
export const darkThemeColors: VisualThemeDesign Token Type Helpers
export type SpacingToken = keyof typeof spacing
export type FontSizeToken = keyof typeof fontSize
export type LineHeightToken = keyof typeof lineHeight
export type FontWeightToken = keyof typeof fontWeight
export type FontFamilyToken = keyof typeof fontFamily
export type IconSizeToken = keyof typeof iconSize
export type BorderRadiusToken = keyof typeof borderRadius
export type DesignToken = keyof typeof tokensVisual framing contracts
VegaVisual and DataGrid share these renderer-facing framing props:
export interface VisualContainerCapabilities {
/** Adds the built-in Copy Visual action. Defaults to true. */
allowCopyVisual?: boolean;
}
export interface HeaderProps {
/** Title displayed in the frame header. */
title: string;
/** Optional subtitle displayed below the title. */
subtitle?: string;
}
export interface VisualFramingProps {
/** Features enabled on the renderer-created frame. */
visualContainerCapabilities?: VisualContainerCapabilities;
/** Title and optional subtitle for the frame. */
header?: HeaderProps;
/** Removes the renderer-created frame. */
chromeless?: boolean;
/** CSS class applied to the renderer-created frame. */
containerClassName?: string;
}For component behavior and direct usage, see the VisualContainer documentation.
Examples
import { aggregate, convertDataTableToRows, filterRows, formatValue, injectDesignTokens, type DataTable } from '@microsoft/fabric-visuals-core';
const table: DataTable = {
columns: [
{ name: 'region', displayName: 'Region' },
{ name: 'city', displayName: 'City' },
{ name: 'sales', displayName: 'Sales', format: '$#,##0.00', },
{ name: 'year', displayName: 'Year' },
],
rows: [
['West', 'Seattle', 1200, 2024],
['East', 'New York', 900, 2024],
],
};
const rows = convertDataTableToRows(table);
const westOnly = filterRows(table, (row) => row[0] === 'West');
const total = aggregate(table, { column: 'sales', fn: 'sum' });
const label = formatValue(1200, '$#,##0.00');
injectDesignTokens();import { spacing, tokens, lightThemeColors, readCssTheme } from '@microsoft/fabric-visuals-core';
spacing.s; // '8px'
tokens.spacingS; // 'var(--spacing-s)'
lightThemeColors.stroke; // '#e0e0e0'
const theme = readCssTheme(); // `VisualTheme` from document-set CSS variablesTrademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.
Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories in our GitHub organizations.
Please do not report security vulnerabilities through public GitHub issues.
For security reporting information, locations, contact information, and policies, please review the latest guidance for Microsoft repositories at https://aka.ms/SECURITY.md.
Code of conduct
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
