# twblazor > twblazor is a free, open source library of Tailwind CSS components for Blazor (.NET), installed from NuGet as the `twblazor` package. It works in Blazor Web Apps using Interactive Server or Interactive WebAssembly render modes. Components are named `Tw*` (for example `TwButton`, `TwTextfield`, `TwDataTable`) and are styled entirely by a `Theme.cs` file that lives in the consuming app and is generated by the Theme builder at https://twblazor.com/theme. This file is for AI assistants helping developers build apps with the twblazor NuGet package. Follow it exactly. twblazor is NOT MudBlazor, Radzen, Blazorise, Bootstrap or Flowbite: do not use their component names, parameters, services or setup steps. When unsure whether a component or parameter exists, read that component's page below rather than guessing. Every page linked below is plain Markdown and lists the component's examples, keyboard navigation, theme and every parameter it accepts. The same page as HTML is at the same address without `.md`. ## Rules for AI assistants - The theme MUST come from the Theme builder at https://twblazor.com/theme, or be the default `Theme.cs` shown on https://twblazor.com/get-started.md. Never write a `Theme.cs` from scratch, never invent theme classes or properties (for example `TwButtonTheme` members), and never restructure the generated file. - To change brand colours, surfaces, rounding, shadows, the default input or button style, or which components are included, go back to https://twblazor.com/theme, change the settings, press "Generate Theme" and replace the whole `Theme.cs` with the new output. Do not hand-edit colours or class strings in the generated file as a substitute for regenerating it. - The generated `Theme.cs` only contains themes for the components ticked on the builder's "Components" tab. Using a component whose theme was left out throws `InvalidOperationException: No Tw...Theme has been configured on the theme`. The fix is to regenerate the theme with that component ticked, not to write the missing theme by hand. - The Theme builder's file exposes `Theme.CreateTheme`. The default theme on Get Started exposes `Theme.CreateDefaultTheme`. Register whichever one the file actually contains: `builder.Services.AddTwBlazor(_ => { }, Theme.CreateTheme);` - twblazor ships NO pre-built stylesheet. Tailwind cannot read classes from a .dll, so the app's own Tailwind build must scan `Theme.cs` with an `@source` directive. If components render unstyled, the cause is almost always a missing `@source` for `Theme.cs` or a stale `output.css`. - Customise individual instances with component parameters (`Color`, `Variant`, `Dense`, `Class`, and so on) and enums from `TwBlazor.Enums` (for example `Color.Primary`, `ButtonVariant.Outlined`). Do not add global CSS overrides for twblazor's internal markup. - Toasts and dialogs need `` and `` in an interactively rendered layout (`MainLayout.razor`), never in `App.razor`. - Keep the accessibility features the components provide: give inputs a `Label`, give icon-only buttons an accessible label, and do not remove focus styles. ## Getting started Full guide with both hosting models: https://twblazor.com/get-started.md 1. Create a Blazor Web App: - Interactive Server: `dotnet new blazor -o {YourProjectName}` - Interactive WebAssembly: `dotnet new blazor -o {YourProjectName} --interactivity WebAssembly` (this creates a host project `{YourProjectName}` and a client project `{YourProjectName}.Client`) 2. Install the package. With WebAssembly, install it in BOTH projects. ```bash dotnet add package twblazor --version 2.1.2 ``` 3. In `Components/App.razor` (always in the host project) add to ``: ```html ``` and before the Blazor script at the end of ``: ```html ``` `css/output.css` is the app's own Tailwind build from step 8, so it 404s until then. 4. Add to `_Imports.razor` (`Components/_Imports.razor` for Server, `{YourProjectName}.Client/_Imports.razor` for WebAssembly): ```razor @using TwBlazor.Components @using TwBlazor.Enums @using TwBlazor ``` 5. Add the providers to the top of `MainLayout.razor` (`Components/Layout/MainLayout.razor` for Server, `{YourProjectName}.Client/Layout/MainLayout.razor` for WebAssembly): ```razor ``` 6. Generate a theme at https://twblazor.com/theme and save it as `Theme.cs` at the root of the project that compiles the components: `{YourProjectName}` for Server, `{YourProjectName}.Client` for WebAssembly. See the rules above. 7. Register the services in `Program.cs`. With WebAssembly, do this in BOTH `Program.cs` files and add `using {YourProjectName}.Client;` to the host project's. ```csharp using TwBlazor; builder.Services.AddTwBlazor(_ => { }, Theme.CreateTheme); ``` 8. Build Tailwind CSS (v4, Tailwind CLI) from the solution root: ```bash npm init -y npm install tailwindcss @tailwindcss/cli ``` Create `{YourProjectName}/wwwroot/css/input.css`. Server: ```css @import "tailwindcss"; @source "../../**/*.razor"; @source "../../Theme.cs"; ``` WebAssembly (the sources must reach into the client project): ```css @import "tailwindcss"; @source "../../**/*.razor"; @source "../../../{YourProjectName}.Client/**/*.razor"; @source "../../../{YourProjectName}.Client/Theme.cs"; ``` Then copy the keyframes (`tw-wave`, `tw-icon-pulse`, `tw-rating-pop`) from step 8 of https://twblazor.com/get-started.md into the end of `input.css`. They power `TwSkeleton`'s wave, `TwProgress`'s shimmer, `TwIcon`'s pulse and `TwRating`'s pop animations. Build it (add `--watch` while developing): - Server: `npx @tailwindcss/cli -i ./wwwroot/css/input.css -o ./wwwroot/css/output.css` - WebAssembly: `npx @tailwindcss/cli -i ./{YourProjectName}/wwwroot/css/input.css -o ./{YourProjectName}/wwwroot/css/output.css` 9. Check it works with a page using `@rendermode InteractiveServer` (or `InteractiveWebAssembly`, placed in the client project): ```razor It works. @code { private int count; private bool enabled; } ``` ## Documentation - [Theme builder](https://twblazor.com/theme): pick brand colours, surfaces, defaults and components, then generate `Theme.cs`. The only supported way to create or change a theme. It is an interactive page, so it has no Markdown version. - [Get Started](https://twblazor.com/get-started.md): Install twblazor in a Blazor Server or WebAssembly app: add the NuGet package, imports, providers and a theme, register AddTwBlazor and build your Tailwind CSS. - [AI Agents & Skills](https://twblazor.com/ai-agents.md): Help AI coding assistants write correct twblazor code with llms.txt, a Markdown copy of every docs page and Agent Skills for Claude Code. - [Class Merge](https://twblazor.com/class-merge.md): How twblazor merges conflicting Tailwind classes so the last one wins, and how to turn it off or add your own utilities with TwBlazorOptions.ClassMerge. - [TwDirectionProvider](https://twblazor.com/direction-provider.md): TwDirectionProvider sets a Blazor app, or part of a page, to right to left or left to right, mirroring layout and arrow keys for Arabic and Hebrew. - [Localization](https://twblazor.com/localization.md): Translate twblazor components and set date and time formats: built in languages, your own .resx files, and options.Localization in AddTwBlazor. - [Tailwind CSS with Blazor](https://twblazor.com/tailwind-blazor.md): How to use Tailwind CSS with Blazor Server and WebAssembly, and how twblazor gives you accessible, themeable Tailwind Blazor components. - [Why twblazor?](https://twblazor.com/why-twblazor.md): twblazor is the MIT licensed Blazor component library built on Tailwind CSS. Free, fully themeable and styled in your own project. ## Agent skills The same guidance packaged as Agent Skills. Download [every skill in one zip](https://twblazor.com/skills/twblazor-skills.zip) and extract it into `.claude/skills/`, or read a skill directly: - [twblazor-components](https://twblazor.com/skills/twblazor-components/SKILL.md): Writes Razor markup with twblazor components such as TwButton, TwTextfield, TwSelect, TwDataTable, TwDialog, toasts and TwChart, using only the parameters each component really has. Use whenever building or changing UI with twblazor, or when converting markup from another Blazor component library to twblazor. - [twblazor-localization](https://twblazor.com/skills/twblazor-localization/SKILL.md): Translates twblazor components and configures date and time formats and right to left layouts, using the 24 built-in languages, the app's own .resx files, options.Localization in AddTwBlazor, a custom ITwLocalizer and TwDirectionProvider. Use when localizing a twblazor app, rewording built-in component text, or supporting Arabic, Hebrew or other right to left languages. - [twblazor-setup](https://twblazor.com/skills/twblazor-setup/SKILL.md): Installs and sets up the twblazor Tailwind CSS component library in a Blazor Server or Blazor WebAssembly app, covering the NuGet package, App.razor links, imports, toast and dialog providers, Theme.cs, AddTwBlazor and the Tailwind build. Use when adding twblazor to a project, or when twblazor components render unstyled or throw on startup. - [twblazor-theming](https://twblazor.com/skills/twblazor-theming/SKILL.md): Creates and changes the Theme.cs that styles every twblazor component, using the twblazor Theme builder for brand colours, surfaces, rounding, shadows, default variants and the components to include, plus dark mode and per-instance Class overrides. Use when theming twblazor, changing its look, adding a component to the theme or fixing a missing component theme. ## Layout - [Breadcrumb](https://twblazor.com/breadcrumb.md) `TwBreadcrumb`: TwBreadcrumb is a Blazor breadcrumb component that shows the current page location. Build trails automatically with Auto, or manually with Label, Href and Icon. - [Card](https://twblazor.com/card.md) `TwCard`: TwCard is a Blazor card component for grouping content. Set Title, HeaderContent and Bordered, or lay cards out in a responsive grid. - [Carousel](https://twblazor.com/carousel.md) `TwCarousel`: TwCarousel is a Blazor carousel component. Bind SelectedIndex and configure AutoPlay, AutoPlayInterval, Loop, ShowArrows, ShowIndicators and swipe gestures. - [Collapse](https://twblazor.com/collapse.md) `TwCollapse`: TwCollapse is a Blazor collapse component that expands and hides content. Bind IsOpen, set Title or HeaderContent, and react to OnToggle. - [Footer](https://twblazor.com/footer.md) `TwFooter`: TwFooter is an accessible Blazor page footer with columns of links, a brand slot, free-form content and a bottom row for copyright and legal links. - [Menu](https://twblazor.com/menu.md) `TwMenu`: TwMenu is a Blazor menu button component that opens a keyboard friendly menu of actions, tick options and labelled groups. - [Navbar](https://twblazor.com/navbar.md) `TwNavbar`: TwNavbar is a responsive Blazor navbar with BrandContent, NavigationContent and ActionsContent slots, data-driven NavigationItems and keyboard support. - [On This Page](https://twblazor.com/on-this-page.md) `TwOnThisPage`: TwOnThisPage is a Blazor table of contents component: an On this page list of section links that highlights the section being read as you scroll. - [Sidebar](https://twblazor.com/sidebar.md) `TwSidebar`: TwSidebar is a Blazor sidebar for navigation. Build it from SidebarContent markup or data-driven NavigationItems, with IsSearchable and a collapsible layout. - [Stepper](https://twblazor.com/stepper.md) `TwStepper`: TwStepper is a Blazor stepper for multi-step flows. Bind ActiveStepIndex, set Orientation, Linear and Color, and give each step a Label and Description. - [Tabs](https://twblazor.com/tabs.md) `TwTabContainer`: TwTabs is a Blazor tabs component, built from TwTabContainer and TwTab. Set Label, Color, Dense and Disabled, and colour the whole container or single tabs. - [Tree List](https://twblazor.com/tree-list.md) `TwTreeList`: TwTreeList is a Blazor tree view for nested, expandable data. Set Label, Icon and Disabled per node, show checkboxes, and bind Checked and Collapsed. ## Forms - [Button](https://twblazor.com/button.md) `TwButton`: TwButton is a Blazor button component. Use Variant, Color, StartIcon, EndIcon, Href, Disabled and IconButton, or group buttons horizontally or vertically. - [Checkbox](https://twblazor.com/checkbox.md) `TwCheckbox`: TwCheckbox is a Blazor checkbox component. Bind Value or SelectedValues, set Color, Size, Disabled and Horizontal, or generate a group from Items. - [Color Picker](https://twblazor.com/color-picker.md) `TwColorPicker`: TwColorPicker is a Blazor colour picker component. Bind Value, choose an OutputFormat, and toggle ShowAlpha and ShowModeSwitch. Supports input variants. - [Date & Time Pickers: Date](https://twblazor.com/date-picker.md) `TwDatePicker`: TwDatePicker is a Blazor date picker component with a calendar popup. Bind Value, set MinDate, MaxDate, Format and Placeholder, or use the native input. - [Date & Time Pickers: Date Range](https://twblazor.com/date-range-picker.md) `TwDateRangePicker`: TwDateRangePicker is a Blazor date range picker with a two-month calendar popup. Bind Value or SelectedRange and constrain it with MinDate and MaxDate. - [Date & Time Pickers: Datetime](https://twblazor.com/datetime-picker.md) `TwDateTimePicker`: TwDateTimePicker is a Blazor component for choosing a date and time in one input. Bind Value, set Format and Placeholder, and use PreferNativePicker on mobile. - [Date & Time Pickers: Datetime Range](https://twblazor.com/datetime-range-picker.md) `TwDateTimeRangePicker`: TwDateTimeRangePicker is a Blazor component for choosing a start and end date and time from one popover. Bind Value, set MinDate, MaxDate and Format. - [Date & Time Pickers: Time](https://twblazor.com/time-picker.md) `TwTimePicker`: TwTimePicker is a Blazor time picker component with 12 hour and 24 hour formats. Bind Value or SelectedTime, and set Placeholder and Variant. - [Date & Time Pickers: Time Range](https://twblazor.com/time-range-picker.md) `TwTimeRangePicker`: TwTimeRangePicker is a Blazor component for choosing a start and end time from one popover. Bind Value or SelectedRange and set Format and Placeholder. - [File Upload](https://twblazor.com/file-upload.md) `TwFileUpload`: TwFileUpload is a Blazor file upload component. Bind Files, restrict types with AllowedFileTypes, allow Multiple files and handle OnChange. - [Numeric](https://twblazor.com/numeric.md) `TwNumeric`: TwNumeric is a Blazor number input component. Bind any numeric type, set Min, Max and Step, format by culture, and add a prefix, suffix or clear button. - [Radio Button](https://twblazor.com/radio-button.md) `TwRadioButton`: TwRadioButton is a Blazor radio button component. Bind SelectedValue, set Color, Disabled and Horizontal, or generate a group from Items. - [Rating](https://twblazor.com/rating.md) `TwRating`: TwRating is a Blazor star rating component. Bind Value, set Min and Max, rate in whole or half steps and swap in any icon. - [Select](https://twblazor.com/select.md) `TwSelect`: TwSelect is a Blazor select component for complex objects and numbers. Bind SelectedValue, or SelectedValues with Multiple, and set Placeholder and Required. - [Slider](https://twblazor.com/slider.md) `TwSlider`: TwSlider is a Blazor slider component for choosing a number in a range. Bind Value and set Min, Max, Step and Color. - [Switch](https://twblazor.com/switch.md) `TwSwitch`: TwSwitch is a Blazor toggle switch component for on and off settings. Bind Value and set Color, Name, and disabled or readonly states. - [Textfield](https://twblazor.com/textfield.md) `TwTextfield`: TwTextfield is a Blazor text input component. Bind Value, use Multiline for a textarea, add a clear button with Clearable, and validate with Validator. ## Feedback - [Alert](https://twblazor.com/alert.md) `TwAlert`: TwAlert is a Blazor alert component for status messages. Set Color, Dense, StartIcon and EndIcon, and make it Dismissible with a bindable Dismissed value. - [Avatar](https://twblazor.com/avatar.md) `TwAvatar`: TwAvatar is a Blazor avatar component that shows a picture, initials or an icon for a person. Set Src, Name, Initials, Icon, Color and Size. - [Chip](https://twblazor.com/chip.md) `TwChip`: TwChip is a Blazor chip component for tags and filters. Set Label, Color, Variant, Size, StartIcon, Avatar and Href, or make it Closable with OnClose. - [Icon](https://twblazor.com/icon.md) `TwIcon`: TwIcon is a Blazor icon component for Bootstrap Icons. Pass an Icon enum value, style it with Tailwind classes, or add OnClick to make an icon button. - [Progress](https://twblazor.com/progress.md) `TwProgress`: TwProgress is a Blazor progress bar component. Set Value, Max, Color and Size, or use Indeterminate mode when the duration is unknown. - [Skeleton](https://twblazor.com/skeleton.md) `TwSkeleton`: TwSkeleton is a Blazor loading placeholder. Choose a SkeletonType and Animation, set Width and Height, or generate one from ChildContent while Loading. - [Spinner](https://twblazor.com/spinner.md) `TwSpinner`: TwSpinner is a Blazor loading spinner component. Set Size, Color, Label and ShowLabel, or use it inside a button. - [Tooltip](https://twblazor.com/tooltip.md) `TwTooltip`: TwTooltip is a Blazor tooltip that wraps any content and shows an accessible bubble on hover and focus. Set Text or TooltipContent and a Placement. ## Data - [Data Table](https://twblazor.com/data-table.md) `TwDataTable`: TwDataTable is a Blazor data table component with pagination, search, sortable columns and custom row classes for displaying structured data. - [Pagination](https://twblazor.com/pagination.md) `TwPagination`: TwPagination is a Blazor pagination component. Bind ActivePage and PageSize, set TotalPages and ShowPageSize to split content across pages. - [Pick List](https://twblazor.com/pick-list.md) `TwPickList`: TwPickList is a Blazor dual list-box component for moving items between SourceItems and TargetItems, with move-all buttons, AllowReorder and keyboard support. - [Barcode](https://twblazor.com/barcode.md) `TwBarcode`: TwBarcode is a dependency-free Blazor barcode component. Set Value and Format for Code 128, Code 39, EAN-13, EAN-8 or UPC-A, or use ITwBarcodeService. - [QR Code](https://twblazor.com/qr-code.md) `TwQrCode`: TwQrCode is a Blazor QR code component with no third-party dependencies. Set Value, ErrorCorrection, Size and QuietZone, or build codes with ITwQrCodeService. - [Calendar](https://twblazor.com/calendar.md) `TwCalendar`: TwCalendar is a Blazor Day, Week and Month calendar with drag and drop, all-day events, a built-in create and edit dialog, and configurable event details. - [Table](https://twblazor.com/table.md) `TwTable`: TwTable is a Blazor table component with striped, hoverable, bordered and borderless styles, plus manual pagination. ## Charts - [Overview](https://twblazor.com/chart.md) `TwChart`: TwChart is the Blazor chart container for over fifty chart types. It adds a title, loading state and shared options. Accessible and script-free. - [Area](https://twblazor.com/chart/area.md) `TwAreaChart`: TwAreaChart is a Blazor area chart: a line chart with the space beneath filled. Supports stacked areas and smooth or stepped curves. - [Bar](https://twblazor.com/chart/bar.md) `TwBarChart`: TwBarChart is a Blazor bar chart that compares categories with horizontal bars. Supports grouped, stacked, 100% stacked and diverging layouts. - [Box Plot](https://twblazor.com/chart/box-plot.md) `TwBoxPlotChart`: TwBoxPlotChart is a Blazor box plot that summarises groups of raw values by median, quartiles, whiskers and outliers. - [Bullet](https://twblazor.com/chart/bullet.md) `TwBulletChart`: TwBulletChart is a Blazor bullet chart that benchmarks an actual value against a target, with shaded bands for qualitative ranges. - [Bump](https://twblazor.com/chart/bump.md) `TwBumpChart`: TwBumpChart is a Blazor bump chart that tracks how series rank against each other across categories, with the highest value ranked first. - [Candlestick](https://twblazor.com/chart/candlestick.md) `TwCandlestickChart`: TwCandlestickChart is a Blazor candlestick chart showing the open, high, low and close of each period. Also draws OHLC charts. - [Column](https://twblazor.com/chart/column.md) `TwColumnChart`: TwColumnChart is a Blazor column chart that compares categories with vertical columns. Supports grouped, stacked, 100% stacked and diverging layouts. - [Dot Plot](https://twblazor.com/chart/dot-plot.md) `TwDotPlotChart`: TwDotPlotChart is a Blazor dot plot that compares series by position on a shared line per category. The scale does not need to start at zero. - [Dumbbell](https://twblazor.com/chart/dumbbell.md) `TwDumbbellChart`: TwDumbbellChart is a Blazor dumbbell chart: two dots per category joined by a bar, highlighting the gap between values such as before and after. - [Funnel](https://twblazor.com/chart/funnel.md) `TwFunnelChart`: TwFunnelChart is a Blazor funnel chart showing how much remains at each stage of a process. Invert it to draw a pyramid chart. - [Gantt](https://twblazor.com/chart/gantt.md) `TwGanttChart`: TwGanttChart is a Blazor Gantt chart: a horizontal bar per task from its start date to its end date, showing a schedule and overlaps. - [Gauge](https://twblazor.com/chart/gauge.md) `TwGaugeChart`: TwGaugeChart is a Blazor circular gauge: an arc filled in proportion to one value between a minimum and a maximum. - [Heatmap](https://twblazor.com/chart/heatmap.md) `TwHeatmapChart`: TwHeatmapChart is a Blazor heatmap: a grid of cells whose color intensity shows the value where a row and a column meet. - [Histogram](https://twblazor.com/chart/histogram.md) `TwHistogramChart`: TwHistogramChart is a Blazor histogram that groups raw values into equal-width bins to reveal the shape of a distribution. - [Icon](https://twblazor.com/chart/icon.md) `TwIconChart`: TwIconChart is a Blazor icon chart and pictogram: values shown as rows of repeated icons, or as one icon sized by each value. - [Line](https://twblazor.com/chart/line.md) `TwLineChart`: TwLineChart is a Blazor line chart for trends. Supports straight, smooth (spline) and step lines, markers and gaps for missing values. - [Lollipop](https://twblazor.com/chart/lollipop.md) `TwLollipopChart`: TwLollipopChart is a Blazor lollipop chart: a thin stem and a dot per value. A lighter alternative to bars when there are many categories. - [Matrix](https://twblazor.com/chart/matrix.md) `TwMatrixChart`: TwMatrixChart is a Blazor matrix chart: a grid with a dot sized by value where a row and a column meet, for two categorical dimensions. - [Nightingale](https://twblazor.com/chart/nightingale.md) `TwNightingaleChart`: TwNightingaleChart is a Blazor Nightingale (rose) chart: equal-angle wedges whose radius shows each value, suited to cyclical data. - [Parallel Coordinates](https://twblazor.com/chart/parallel-coordinates.md) `TwParallelCoordinatesChart`: TwParallelCoordinatesChart is a Blazor parallel coordinates chart: one axis per variable and a line per item, each axis on its own scale. - [Pie](https://twblazor.com/chart/pie.md) `TwPieChart`: TwPieChart is a Blazor pie chart for parts of a whole. Set an inner radius for a donut chart, or draw it as a semicircle. - [Quadrant](https://twblazor.com/chart/quadrant.md) `TwQuadrantChart`: TwQuadrantChart is a Blazor quadrant chart: a scatter plot split into four labelled regions by two thresholds, for sorting items into groups. - [Radar](https://twblazor.com/chart/radar.md) `TwRadarChart`: TwRadarChart is a Blazor radar (spider) chart that compares a few items across several attributes on spokes around a center. - [Radial Bar](https://twblazor.com/chart/radial-bar.md) `TwRadialBarChart`: TwRadialBarChart is a Blazor radial bar chart: bars bent around a circle, one ring per value, each sweeping further for larger values. - [Range](https://twblazor.com/chart/range.md) `TwRangeChart`: TwRangeChart is a Blazor range chart that draws a floating bar from a low value to a high value per category, such as salary bands. - [Scatter](https://twblazor.com/chart/scatter.md) `TwScatterChart`: TwScatterChart is a Blazor scatter plot that positions points by two values. Also draws bubble charts and connected scatter plots. - [Slope](https://twblazor.com/chart/slope.md) `TwSlopeChart`: TwSlopeChart is a Blazor slope chart: a labelled line per series between two points in time, showing the direction and size of each change. - [Small Multiples](https://twblazor.com/chart/small-multiples.md) `TwSmallMultiplesChart`: TwSmallMultiplesChart is a Blazor small multiples chart: one small panel per series on a shared scale, for comparing many series clearly. - [Strip Plot](https://twblazor.com/chart/strip-plot.md) `TwStripPlotChart`: TwStripPlotChart is a Blazor strip plot that draws every observation as a dot, one strip per group. Add jitter to separate overlaps. - [Treemap](https://twblazor.com/chart/treemap.md) `TwTreemapChart`: TwTreemapChart is a Blazor treemap: rectangles that tile the plot, each sized by its value, showing many parts of a whole compactly. - [Waffle](https://twblazor.com/chart/waffle.md) `TwWaffleChart`: TwWaffleChart is a Blazor waffle chart: a ten by ten grid of squares, each worth one percent, colored by each value's share. - [Waterfall](https://twblazor.com/chart/waterfall.md) `TwWaterfallChart`: TwWaterfallChart is a Blazor waterfall chart: floating columns that show how increases and decreases build up to a total. - [Arc Diagram](https://twblazor.com/chart/arc-diagram.md) `TwArcDiagramChart`: TwArcDiagramChart is a Blazor arc diagram: nodes set out along a line and joined by an arc for every link. - [Barcode](https://twblazor.com/chart/barcode.md) `TwBarcodeChart`: TwBarcodeChart is a Blazor barcode chart that draws a thin line for every raw observation along one axis, so clusters and gaps stand out. - [Beeswarm](https://twblazor.com/chart/beeswarm.md) `TwBeeswarmChart`: TwBeeswarmChart is a Blazor beeswarm chart that draws every observation as a dot, nudged sideways so none overlap. - [Bump Area](https://twblazor.com/chart/bump-area.md) `TwBumpAreaChart`: TwBumpAreaChart is a Blazor bump area chart: a band per series that is as thick as its value and moves as its rank changes. - [Categorical Scatter](https://twblazor.com/chart/categorical-scatter.md) `TwCategoricalScatterChart`: TwCategoricalScatterChart is a Blazor chart that places a dot where two categories meet and sizes it by a value. - [Chord Diagram](https://twblazor.com/chart/chord-diagram.md) `TwChordDiagramChart`: TwChordDiagramChart is a Blazor chord diagram: nodes as arcs around a circle joined by ribbons as thick as the flow between them. - [Circular Treemap](https://twblazor.com/chart/circular-treemap.md) `TwCircularTreemapChart`: TwCircularTreemapChart is a Blazor circle packing chart: a circle per leaf of a tree, sized by value and packed inside its parent's circle. - [Contour](https://twblazor.com/chart/contour.md) `TwContourChart`: TwContourChart is a Blazor contour plot that joins the places where a measured surface has the same value, like height lines on a map. - [Convex Treemap](https://twblazor.com/chart/convex-treemap.md) `TwConvexTreemapChart`: TwConvexTreemapChart is a Blazor treemap for trees: cut-cornered tiles sized by value and grouped with the other leaves of their parent. - [Density Plot](https://twblazor.com/chart/density-plot.md) `TwDensityPlotChart`: TwDensityPlotChart is a Blazor density plot that draws a smooth curve per group showing where its raw values concentrate. - [Dendrogram](https://twblazor.com/chart/dendrogram.md) `TwDendrogramChart`: TwDendrogramChart is a Blazor dendrogram: a tree drawn from its root down to its leaves with a bracket joining every branch to its parent. - [Euler Diagram](https://twblazor.com/chart/euler-diagram.md) `TwEulerDiagramChart`: TwEulerDiagramChart is a Blazor Euler diagram: sets as circles sized by their members, overlapping only where they share some. - [Flowchart](https://twblazor.com/chart/flowchart.md) `TwFlowchart`: TwFlowchart is a Blazor flowchart: the steps of a process as boxes in columns, with an arrow for every link from one step to the next. - [Hexagonal Binning](https://twblazor.com/chart/hexbin.md) `TwHexbinChart`: TwHexbinChart is a Blazor hexbin chart that tiles the plot with hexagons shaded by how many points fall in each, for scatter data too dense to read. - [Horizon](https://twblazor.com/chart/horizon.md) `TwHorizonChart`: TwHorizonChart is a Blazor horizon chart that folds each series into a compact row of layered bands, fitting many series into little height. - [Marimekko](https://twblazor.com/chart/marimekko.md) `TwMarimekkoChart`: TwMarimekkoChart is a Blazor Marimekko chart: columns whose widths show each category's total and whose segments show each series' share of it. - [Network Diagram](https://twblazor.com/chart/network-diagram.md) `TwNetworkDiagramChart`: TwNetworkDiagramChart is a Blazor network diagram that arranges linked nodes close together and unrelated ones apart. - [Radial Histogram](https://twblazor.com/chart/radial-histogram.md) `TwRadialHistogramChart`: TwRadialHistogramChart is a Blazor radial histogram that wraps equal-width bins around a circle, for cyclical values such as hours or bearings. - [Ridgeline](https://twblazor.com/chart/ridgeline.md) `TwRidgelinePlotChart`: TwRidgelinePlotChart is a Blazor ridgeline plot that gives each group its own row and density curve, for comparing many distributions. - [Sankey](https://twblazor.com/chart/sankey.md) `TwSankeyChart`: TwSankeyChart is a Blazor Sankey diagram: nodes in columns joined by ribbons as thick as the flow between them. - [Stream Graph](https://twblazor.com/chart/stream-graph.md) `TwStreamGraphChart`: TwStreamGraphChart is a Blazor stream graph: stacked layers that flow around a central line to show how the make-up of a total shifts over time. - [Sunburst](https://twblazor.com/chart/sunburst.md) `TwSunburstChart`: TwSunburstChart is a Blazor sunburst chart: a tree drawn as rings, each segment sized by its share of the whole. - [Venn Diagram](https://twblazor.com/chart/venn-diagram.md) `TwVennDiagramChart`: TwVennDiagramChart is a Blazor Venn diagram: up to three sets as equal overlapping circles, with the shared count where each pair meets. - [Violin Plot](https://twblazor.com/chart/violin-plot.md) `TwViolinPlotChart`: TwViolinPlotChart is a Blazor violin plot that shows the full shape of each group's distribution with its median and middle half marked. - [Word Cloud](https://twblazor.com/chart/word-cloud.md) `TwWordCloudChart`: TwWordCloudChart is a Blazor word cloud: words sized by their values and gathered around the middle of the plot. ## Services - [Dialog Service](https://twblazor.com/dialog.md) `TwDialog`: TwDialog is a Blazor dialog service for modal windows. Open any component with ITwDialogService.ShowAsync, return data, and set position, size and behaviour. - [Toast Service](https://twblazor.com/toast.md) `TwToastProvider`: TwToast is a Blazor toast notification service. Call ITwToastService.Show with a message, title, Color and icon, with duration, persistence and custom toasts. ## Optional - [Everything in one file](https://twblazor.com/llms-full.txt): this file followed by every page below in full. - [API reference](https://twblazor.github.io/twblazor/): generated API documentation for every public type. - [NuGet package](https://www.nuget.org/packages/twblazor) - [Source code](https://github.com/TwBlazor/twblazor) --- # AI Agents & Skills > Help AI coding assistants write correct twblazor code with llms.txt, a Markdown copy of every docs page and Agent Skills for Claude Code. Documentation page: https://twblazor.com/ai-agents ## Overview AI coding assistants often guess at a component library: they invent parameters, borrow another library's setup steps or write a theme by hand. twblazor publishes everything an assistant needs in the formats assistants read, so it can use the real components from the first try. All of it is generated from these docs every time the site is built. Each component's parameters come straight from the library's own source, so an assistant only ever sees components and parameters that exist in the current release. ## llms.txt `llms.txt` is a plain text index written for language models. It sets out the rules for using twblazor, the setup steps and a link to the Markdown page of every component and guide. **The files published for AI assistants** | File | What it holds | | --- | --- | | [`/llms.txt`](https://twblazor.com/llms.txt) | The rules, the setup steps and a link to every page. Start here. | | [`/llms-full.txt`](https://twblazor.com/llms-full.txt) | `llms.txt` followed by every page in full, for assistants that read one file. | | [`/button.md`](https://twblazor.com/button.md) | Any docs page as Markdown: add `.md` to its address. Component pages list their examples, keyboard navigation, theme and every parameter. | ## Point your assistant at llms.txt Add these lines to the instructions file your assistant reads, such as `CLAUDE.md`, `AGENTS.md`, `.github/copilot-instructions.md` or a Cursor rule. Any assistant that can fetch a web page will then look things up instead of guessing. ```markdown ## twblazor This project uses the twblazor component library. Before writing or changing twblazor code, read https://twblazor.com/llms.txt and the Markdown page of each component you use. Use only the parameters those pages list, and never write Theme.cs by hand: generate it at https://twblazor.com/theme. ``` ## Agent skills A skill is a folder with a `SKILL.md` file and the reference pages it needs. The assistant reads only each skill's short description up front, and loads the rest when a task calls for it, so a skill adds detailed guidance without filling the context. Each twblazor skill bundles the Markdown pages it refers to, so it also works offline. **The twblazor agent skills** .zip | Download every skill in one zip ## Install the skills in Claude Code Extract the zip into `.claude/skills` at the root of your project. Commit the folder and everyone working on the project gets the skills too. To use them in every project instead, extract it into `~/.claude/skills` in your home folder. macOS and Linux: ```bash curl -L -o twblazor-skills.zip https://twblazor.com/skills/twblazor-skills.zip mkdir -p .claude/skills unzip -o twblazor-skills.zip -d .claude/skills rm twblazor-skills.zip ``` Windows PowerShell: ```powershell Invoke-WebRequest https://twblazor.com/skills/twblazor-skills.zip -OutFile twblazor-skills.zip Expand-Archive twblazor-skills.zip -DestinationPath .claude/skills -Force Remove-Item twblazor-skills.zip ``` Claude Code finds the skills when a session starts and uses them whenever a task matches their descriptions, such as adding twblazor to a project or building a form. Run the same commands again after upgrading twblazor to pick up the new release. ## Use the skills in the Claude apps Download a single skill's zip from the table above and upload it in the skills section of Claude's settings. Upload each skill you want separately, since an upload holds one skill. ## Other assistants The skills use the open Agent Skills format: a folder holding a `SKILL.md` with a name and description. Assistants that support the format can read the same folders from their own skills directory. For an assistant that does not, use the `llms.txt` instructions above. ## How they stay accurate - The pages, the component list and the descriptions come from these docs and from `components.json`, the same source as the sidebar. - Every parameter table is read from the `[Parameter]` properties and XML documentation in the library's source. - The install command names the same version as the [Get started](https://twblazor.com/get-started.md) guide, which moves with every release. - The code samples are the same samples these pages render live, so they compile with the current release. --- # TwAlert > TwAlert is a Blazor alert component for status messages. Set Color, Dense, StartIcon and EndIcon, and make it Dismissible with a bindable Dismissed value. Documentation page: https://twblazor.com/alert ## Alert Provide contextual feedback messages for typical user actions with the handful of available and flexible alert messages. ```razor

This is an example alert with a link.

``` ## Colors TwAlert supports all the standard theme colors via the `Color` property. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color))).Take(10)) { @c.ToString() } ``` ## Announcements A screen reader announces an alert when it appears. An error or a warning (`Color.Danger`, `Color.Warning`) interrupts with `role="alert"`; every other color waits its turn with `role="status"`. Set `Role` to choose for yourself, or to `none` for an alert that is part of the page from the start and should be read in place like any other content. ```razor Saved. Announced when the screen reader is idle. Payment failed. Announced at once. Prices include tax. Read in place, never announced. ``` ## Dense alerts You can also make alerts dense and take up less space using the `Dense` property. ```razor
This is a dense alert. This is another dense alert.
``` ## Alert icons TwAlert also supports easy icons parameters `StartIcon` and `EndIcon`. A small padding separates each icon from the text; override it with `StartIconPadding` and `EndIconPadding`. ```razor
This is a dense alert with a start icon. This is another dense alert with an end icon. This is an alert with a start icon. This is another alert with an end icon.
``` ## Dismissible alerts You can also make alerts dismissible by using `OnDismiss` or the `Dismissible` property set as true, setting `Dismissible` to true will show the X button and won't require an event callback. ```razor This is a dense alert that is dismissible. ``` ```csharp private void HandleDismiss() => ToastService.ShowInfo("Alert dismissed!", "You have dismissed the alert."); ``` ## Keyboard navigation An alert is read out by screen readers when it appears. Only a dismissible alert has a control to focus. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the dismiss button. | | `Enter` or `Space` | Dismisses the alert. Focus moves to the next control on the page. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwAlert Represents an alert component that displays informational messages to users. | Parameter | Type | Description | | --- | --- | --- | | `Text` | `string?` | Gets or sets the text content to display in the alert. | | `StartIcon` | `Icon?` | Gets or sets the icon to display at the start of the alert. | | `EndIcon` | `Icon?` | Gets or sets the icon to display at the end of the alert. | | `StartIconPadding` | `string?` | Gets or sets the Tailwind padding classes between the start icon and the text. Defaults to the theme's small padding when not set. | | `EndIconPadding` | `string?` | Gets or sets the Tailwind padding classes between the text and the end icon. Defaults to the theme's small padding when not set. | | `OnDismiss` | `EventCallback` | Gets or sets the callback that is invoked when the alert is dismissed. | | `Dismissible` | `bool` | Gets or sets a value indicating whether the alert can be dismissed by the user. | | `Dismissed` | `bool` | Gets or sets a value indicating whether the alert is currently dismissed (hidden). | | `Dense` | `bool` | Gets or sets a value indicating whether the alert should use compact padding. | | `DismissedChanged` | `EventCallback` | Gets or sets the callback that is invoked when the Dismissed state changes. | | `ChildContent` | `RenderFragment?` | Gets or sets the custom content to display in the alert. | | `Color` | `Color?` | Gets or sets the color scheme for the alert. | | `Role` | `string?` | Gets or sets the ARIA role of the alert, which decides how a screen reader announces it. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwAlertTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwAlertTheme` by hand. --- # TwAvatar > TwAvatar is a Blazor avatar component that shows a picture, initials or an icon for a person. Set Src, Name, Initials, Icon, Color and Size. Documentation page: https://twblazor.com/avatar ## Basic usage Give `TwAvatar` a `Name` and it shows that person's initials: the first letters of the first and last words. The name also labels the avatar for assistive technology. ```razor
``` ## Picture Set `Src` to show a picture, cropped to the avatar's shape. If the picture fails to load, the avatar falls back to the initials, so keep the `Name` alongside it. ```razor
``` ## Initials Set `Initials` to choose the letters yourself, for example when the name is not a person's. ```razor
``` ## Icon With no picture and no initials the avatar shows an icon. Set `Icon` to change it. ```razor
``` ## Sizes Use `Size` to set the avatar's dimensions. The initials and icon scale with it. ```razor
``` ## Colors Use `Color` to set the background behind the initials or icon. Without one the avatar is a neutral gray. ```razor
@foreach (var color in Enum.GetValues()) { }
``` ## Shape Avatars are round by default. Set `Rounded` for a different shape. ```razor
``` ## Beside a name When the name is written next to the avatar, leave `Name` off and pass `Initials` instead. The avatar is then decoration and is hidden from assistive technology, so the name is not read out twice. ```razor

Jane Doe

Product Designer

``` ## Accessibility An avatar with a `Name` or an `AriaLabel` is exposed as an image with that name, whether it shows a picture, initials or an icon. An avatar with neither is hidden from assistive technology. Give every avatar that stands on its own a name, and leave it off only when the same name is already in the text beside it. ## Keyboard navigation This component is not interactive, so it has no keyboard controls of its own and is not a Tab stop. Anything interactive you place inside it keeps its own keyboard behaviour. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwAvatar Represents a person or an entity with a picture, their initials or an icon. | Parameter | Type | Description | | --- | --- | --- | | `Src` | `string?` | Gets or sets the URL of the picture. | | `Name` | `string?` | Gets or sets the name of the person or entity. It names the avatar for assistive technology and supplies the initials when `Initials` is not set. | | `Initials` | `string?` | Gets or sets the initials shown when there is no picture. | | `Icon` | `Icon` | Gets or sets the icon shown when there is no picture and no initials. | | `Color` | `Color?` | Gets or sets the color behind the initials or icon. | | `Size` | `AvatarSize` | Gets or sets the size of the avatar. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwAvatarTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwAvatarTheme` by hand. --- # TwBarcode > TwBarcode is a dependency-free Blazor barcode component. Set Value and Format for Code 128, Code 39, EAN-13, EAN-8 or UPC-A, or use ITwBarcodeService. Documentation page: https://twblazor.com/barcode ## Basic usage Give `TwBarcode` a `Value` and it draws a Code 128 barcode, which holds any ASCII text. The bars are a single SVG path, so they stay sharp at any size, and the text is printed underneath so it can be typed in if a scan fails. ```razor ``` ## Formats Use `Format` to pick the symbology. `Code128` (the default) suits shipping labels, tickets and tracking numbers. `Code39` holds upper case letters, digits, space and `-.$/+%`, and is read by almost every scanner. `Ean13`, `Ean8` and `UpcA` are retail product codes: give them the digits without the check digit and it is added for you, or with it and it is verified. ```razor
``` ## Live value The barcode is only rebuilt when `Value`, `Format` or `QuietZone` change, so it is cheap to bind to an input. Nothing is drawn while the value is empty or does not suit the format, such as lower case letters in Code 39. ```razor
``` ```csharp private string liveValue = "Hello, TwBlazor"; ``` ## Sizes Use `Size` to set the height of the bars. The width follows from the height and the length of the value, and never grows past its container. ```razor
``` ## Text and quiet zone Set `ShowText="false"` to leave out the printed text. Scanners find the bars by the plain margin either side, called the quiet zone; each format has its own minimum, which is used by default. Only reduce `QuietZone` when the barcode already sits on a plain light background. ```razor
``` ## Colors and dark mode The bars and text are drawn in the current text color over a background, set by `Foreground` and `Background` in `TwBarcodeTheme`, the same settings the QR code uses. By default a barcode stays black on white in dark mode too: unlike QR codes, inverted barcodes (light bars on a dark background) are not read reliably, so treat inverting one as a choice to test with your own scanners. Change the colors for every barcode in your theme, or for a single barcode with `Class`, and keep strong contrast between them. ```razor
``` ## Using the service `ITwBarcodeService` is registered by `AddTwBlazor`. Call it directly to build a barcode outside a component: `Encode` returns a `Barcode` of dark and light modules. Draw it with the shared `SymbolSvg` methods from `TwBlazor.Services.Encoding`, which draw QR codes too: `ToSvg` writes a standalone SVG (with an optional caption) for a file, a label or inline markup, `ToSvgDataUri` gives a download link or image source, and `GetSvgPath` gives the path data for your own markup. `TryEncode` tells you whether a value suits a format without throwing. ```razor
@((MarkupString)serviceSvg)
``` ```csharp private string serviceSvg = string.Empty; private string serviceDataUri = string.Empty; protected override void OnInitialized() { var barcode = BarcodeService.Encode("501234567890", BarcodeFormat.Ean13); var svgOptions = new SymbolSvgOptions { Caption = barcode.Text, Title = $"Barcode: {barcode.Text}" }; serviceSvg = barcode.ToSvg(svgOptions); serviceDataUri = barcode.ToSvgDataUri(svgOptions); } ``` ## Accessibility A barcode is exposed as an image (`role="img"`) named "Barcode: " followed by its text, or after `AriaLabel` or `AriaLabelledBy` when set, and it is not a Tab stop. The printed text is hidden from screen readers so it is not read twice. Its colors opt out of forced colors mode (`forced-color-adjust: none`), because recolored bars may not scan. ## Keyboard navigation A barcode is not interactive and is not a Tab stop. Screen readers announce it as an image named after the text it holds, unless it is given a label of its own. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBarcode Shows a value, such as a product number or tracking reference, as a scannable one-dimensional barcode. | Parameter | Type | Description | | --- | --- | --- | | `Format` | `BarcodeFormat` | Gets or sets the barcode format. | | `ShowText` | `bool` | Gets or sets whether to print the human readable text under the bars. | | `Size` | `BarcodeSize` | Gets or sets the height of the bars. The width follows from it and the length of the value. | | `Value` | `string?` | Gets or sets the value to encode. Nothing is rendered while it is empty or cannot be encoded. | | `QuietZone` | `int?` | Gets or sets the light margin around the symbol, in modules. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwBarcodeTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwBarcodeTheme` by hand. --- # TwBreadcrumb > TwBreadcrumb is a Blazor breadcrumb component that shows the current page location. Build trails automatically with Auto, or manually with Label, Href and Icon. Documentation page: https://twblazor.com/breadcrumb ## Breadcrumbs Usage of breadcrumb is simplified, you can use the component and allow for automatic breadcrumbs based on the current uri structure: ```razor ``` ## Manual breadcrumbs You can also manually configure the breadcrumbs. Give an item an `Icon` to show it before the label, and set `AriaCurrent` on the last one to mark it as the current page: it is then shown as text, not a link, and announced as the current page by screen readers. ```razor ``` ```csharp private readonly List _breadcrumbs = new() { new() { Icon = Icon.House, Label = "Home", Href = "/" }, new () { Icon = Icon.Gear, Label = "Settings", Href = "/" }, new () { Icon = Icon.Person, Label = "Profile", Href = "/", AriaCurrent = true } }; ``` ## Inline breadcrumbs You can also manually configure the breadcrumbs inline like so: ```razor ``` ## Custom separators The separator between breadcrumbs is a `/` by default. Set `Separator` to use any other text, such as a dot: ```razor ``` Set `SeparatorIcon` to use an icon instead, such as a chevron or an arrow. It works with `Breadcrumbs` and `Auto` as well as inline items: ```razor ``` ```razor ``` A `TwBreadcrumbItem` can set its own `Separator` or `SeparatorIcon`, which is shown before that item only. Separators are decorative, so they are hidden from screen readers, which already announce the trail as a list. ```razor ``` ## Keyboard navigation The breadcrumb is a navigation landmark holding ordinary links. The current page is text, not a link. | Key | What it does | | --- | --- | | `Tab` | Moves to the next link. | | `Enter` | Follows the focused link. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBreadcrumb A navigation component which displays an ordered list of the current page navigation. | Parameter | Type | Description | | --- | --- | --- | | `Breadcrumbs` | `List` | The list of breadcrumbs to display. | | `BreadcrumbClass` | `string` | Adds classes to individual breadcrumbs, default value is "capitalize". | | `ChildContent` | `RenderFragment?` | The child content rendered in the ordered list. | | `Auto` | `bool` | Determines if the breadcrumbs are automatically constructed from the URI. | | `Separator` | `string` | Gets or sets the text shown between breadcrumbs. Defaults to `/`. | | `SeparatorIcon` | `Icon?` | Gets or sets an icon shown between breadcrumbs in place of the `Separator` text, such as `Chevron_Right`. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwBreadcrumbItem | Parameter | Type | Description | | --- | --- | --- | | `Breadcrumb` | `BreadcrumbItem?` | Allows for dynamic generation of properties for `TwBreadcrumb` instead of defining them inline. | | `Icon` | `Icon?` | Gets or sets the icon associated with the object. This icon can be used to visually represent the object in a user interface. | | `Label` | `string?` | Gets or sets the label text display associated with the entity. | | `Href` | `string?` | Gets or sets the URI that identifies the resource. | | `AriaCurrent` | `bool` | Gets or sets a value indicating whether the element is the current item within a set of items. | | `IsFirst` | `bool?` | Explicitly overrides whether this is the first breadcrumb in the trail (suppressing its leading separator), bypassing the cascading-parent lookup used for inline (ChildContent) usage. Set by `TwBreadcrumb` when rendering from its `Breadcrumbs` list, where items aren't wrapped in a CascadingValue back to the parent. | | `Separator` | `string?` | Gets or sets the text shown before this breadcrumb, in place of the one set on `TwBreadcrumb`. | | `SeparatorIcon` | `Icon?` | Gets or sets an icon shown before this breadcrumb, in place of the separator set on `TwBreadcrumb`. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwBreadcrumbTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwBreadcrumbTheme` by hand. --- # TwButton > TwButton is a Blazor button component. Use Variant, Color, StartIcon, EndIcon, Href, Disabled and IconButton, or group buttons horizontally or vertically. Documentation page: https://twblazor.com/button ## Buttons Usage of the button component is simple, you can use it to trigger actions. Below are some common actions: ```razor ``` ```csharp public int ClickCount { get; set; } = 0; private void HandleClick() => ClickCount++; ``` ## Icon buttons The button component can also be used with icons only: ```razor ``` ```csharp private bool darkMode { get; set; } private void ToggleMode() => darkMode = !darkMode; ``` ## Tooltips Set `Tooltip` to show a short description when the button is hovered or keyboard-focused. It renders a `role="tooltip"` element linked to the button with `aria-describedby`, stays visible while the pointer moves onto it, and can be dismissed with `Escape`. A tooltip only supplements the accessible name, so icon-only buttons still need an `AriaLabel`. The same `Tooltip` property works on an icon button (`TwIcon` with `OnClick`). ```razor ``` ## Buttons variants & colors There are multiple different button variants. ```razor
@foreach (Color c in Enum.GetValues()) {
}
``` ## Buttons with icons Buttons can include icons at the start or end for better visual communication: ```razor
``` ## All colors Buttons support all color themes from the color palette: ```razor
@foreach (Color c in Enum.GetValues()) { }
``` ## Button states Buttons can be disabled or set to readonly mode: ```razor
``` ## Basic button groups Group related buttons together with consistent spacing. ```razor ``` ## Vertical button groups Stack buttons vertically. ```razor ``` ## Full width button groups Make buttons fill the container width equally. ```razor ``` ## Keyboard navigation A button is a native button, or a native link when it has an Href. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the button. A read-only button stays focusable and is announced as unavailable. | | `Enter` or `Space` | Activates the button. | | `Escape` | Hides the button's tooltip, if it has one. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwButton Represents a configurable button component that supports custom content, navigation, and event handling in a Blazor application. | Parameter | Type | Description | | --- | --- | --- | | `OnClick` | `EventCallback` | Gets or sets the callback that is invoked when the button is clicked. | | `Label` | `string` | Gets or sets the text label to display for the button. | | `Type` | `string` | The type of button (e.g., "button", "submit", "reset"). | | `Color` | `Color?` | Gets or sets the color theme of the button. | | `Variant` | `ButtonVariant?` | Gets or sets the button variant. | | `StartIcon` | `Icon?` | Gets or sets whether to display an icon at the start of the button. | | `EndIcon` | `Icon?` | Gets or sets whether to display an icon at the end of the button. | | `Href` | `string` | Sets the button to use `NavigationManager`. | | `Disabled` | `bool` | Disables the button if set to true. | | `Readonly` | `bool` | Makes the button readonly if set to true. | | `Dense` | `bool` | Gets or sets a value indicating whether the component should be displayed in a dense layout. | | `ChildContent` | `RenderFragment?` | Gets or sets the custom content to display in the button. | | `Target` | `string` | Gets or sets the name of the target frame or window for the navigation request. | | `IconButton` | `bool` | Gets or sets a value indicating whether padding is removed from the content. | | `Plain` | `bool` | When true, skips the button's base structural classes (sizing/shape), typography, variant/color classes, focus ring, and shadow - leaving only `Class` (and the disabled/readonly cursor class) applied. | | `Tooltip` | `string?` | Gets or sets the text of a tooltip shown when the button is hovered or keyboard-focused. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwButtonGroup Represents a container component for grouping multiple `TwButton` components together. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the content to display within the button group. | | `Legend` | `string?` | Gets or sets the legend text for the button group. | | `LegendClass` | `string?` | Gets or sets the CSS class for the legend element. | | `Vertical` | `bool` | Gets or sets the orientation of the button group. | | `FullWidth` | `bool` | Gets or sets whether buttons should take full width of the container. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwButtonTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwButtonTheme` by hand. --- # TwCalendar > TwCalendar is a Blazor Day, Week and Month calendar with drag and drop, all-day events, a built-in create and edit dialog, and configurable event details. Documentation page: https://twblazor.com/calendar ## Views Bind `SelectedDate` and `View` to switch between Day, Week and Month. The header names what you're looking at: the day, the week or the month. "Today" is on the left and the previous and next buttons are on the right. Events that overlap in time sit side by side. The Day and Week grids scroll once they pass `MaxHeight` (`40rem` by default), and you can pass any CSS length, such as `"30rem"` or `"600px"`. They open scrolled to `ScrollToTime`, 8am by default, so you land on the working day instead of midnight. Click an event to see its details. This calendar isn't editable, so every event opens read-only, and the extra details come from `DialogProperties` (see "Event Details in the Dialog" below). ```razor ``` ```csharp private DateTime selectedDate = DateTime.Today; private TwCalendarView view = TwCalendarView.Week; private readonly List> _schedules = BuildSampleSchedules(); public enum EventPriority { Low, Medium, High } public class EventDetails { public string? Notes { get; set; } public string? Location { get; set; } public string? Organizer { get; set; } public int Attendees { get; set; } public EventPriority Priority { get; set; } public bool IsOnline { get; set; } } private readonly Dictionary _dialogProperties = new() { [nameof(EventDetails.Notes)] = "Notes", [nameof(EventDetails.Location)] = "Location", [nameof(EventDetails.Organizer)] = "Organizer", [nameof(EventDetails.Attendees)] = "Attendees", [nameof(EventDetails.Priority)] = "Priority", [nameof(EventDetails.IsOnline)] = "Online meeting" }; private static Schedule Event(string name, int dayOffset, double startHour, double hours, string color, EventDetails details, bool readOnly = false) { var start = DateTime.Today.AddDays(dayOffset).AddHours(startHour); return new() { Name = name, DateTimeStart = start, DateTimeEnd = start.AddHours(hours), Color = color, ReadOnly = readOnly, Value = details }; } private static Schedule AllDay(string name, int firstDayOffset, int days, string color, EventDetails details) { var start = DateTime.Today.AddDays(firstDayOffset); return new() { Name = name, DateTimeStart = start, DateTimeEnd = start.AddDays(days), Color = color, Value = details }; } private static List> BuildSampleSchedules() => [ Event("Team standup", 0, 9, 0.5, "#2563eb", new() { Notes = "Quick round of blockers. Keep it to 15 minutes.", Location = "Meeting room 2", Organizer = "Priya Shah", Attendees = 8, Priority = EventPriority.Medium }), Event("Design review", 0, 10, 1, "#9333ea", new() { Notes = "Walk through the new dashboard mockups and collect feedback.", Location = "Studio", Organizer = "Marcus Lee", Attendees = 6, Priority = EventPriority.High, IsOnline = true }), Event("1:1 with Sam", 0, 10.5, 0.75, "#db2777", new() { Notes = "Talk about the Q4 goals and the conference talk.", Organizer = "Jordan Ellis", Attendees = 2, Priority = EventPriority.Medium, IsOnline = true }), Event("Lunch", 0, 12, 1, "#f59e0b", new() { Notes = "Team lunch. Booked under Shuter.", Location = "The Corner Cafe", Organizer = "Office team", Attendees = 12, Priority = EventPriority.Low }, readOnly: true), Event("Customer demo", 0, 15, 1, "#0d9488", new() { Notes = "Show the new reporting module to the Hartley account team.", Location = "Meeting room 1", Organizer = "Aisha Khan", Attendees = 5, Priority = EventPriority.High, IsOnline = true }), Event("Code review", 0, 16.5, 0.5, "#4f46e5", new() { Notes = "Pairing session on the payments refactor.", Organizer = "Tom Becker", Attendees = 3, Priority = EventPriority.Low, IsOnline = true }), Event("OKR workshop", 1, 10, 2, "#7c3aed", new() { Notes = "Draft next quarter's objectives. Bring your team's draft key results.", Location = "Main hall", Organizer = "Priya Shah", Attendees = 24, Priority = EventPriority.High }), Event("Sprint planning", 1, 14, 1.5, "#16a34a", new() { Notes = "Bring estimates for the top ten backlog items.", Location = "Meeting room 1", Organizer = "Marcus Lee", Attendees = 9, Priority = EventPriority.Medium }), AllDay("Company holiday", 1, 1, "#f59e0b", new() { Notes = "Offices are closed. Support is on call.", Organizer = "People team", Attendees = 120, Priority = EventPriority.Low }), Event("Client call", 2, 9, 0.75, "#0d9488", new() { Notes = "Share the revised timeline and ask about the sign-off date.", Organizer = "Aisha Khan", Attendees = 4, Priority = EventPriority.High, IsOnline = true }), Event("Workshop prep", 2, 13, 1, "#be185d", new() { Notes = "Print the handouts and test the projector.", Location = "Meeting room 2", Organizer = "Jordan Ellis", Attendees = 2, Priority = EventPriority.Low }), AllDay("Product conference", 2, 3, "#be185d", new() { Notes = "Three days of talks. Our slot is on the second morning.", Location = "Convention centre", Organizer = "Events team", Attendees = 40, Priority = EventPriority.High }), Event("Budget review", 3, 9, 0.5, "#0891b2", new() { Notes = "Check spend against the quarterly forecast.", Location = "Finance office", Organizer = "Rhea Patel", Attendees = 5, Priority = EventPriority.Medium }), Event("Interview", 3, 10, 0.5, "#7c3aed", new() { Notes = "Frontend candidate, second round. Questions are in the hiring doc.", Location = "Meeting room 1", Organizer = "Tom Becker", Attendees = 3, Priority = EventPriority.Medium }), Event("All hands", 3, 11, 1, "#ea580c", new() { Notes = "Company update and Q&A with the leadership team.", Location = "Main hall", Organizer = "Leadership team", Attendees = 120, Priority = EventPriority.High, IsOnline = true }), Event("Extra sync", 3, 13, 0.5, "#059669", new() { Notes = "Follow up on the open questions from the all hands.", Organizer = "Priya Shah", Attendees = 4, Priority = EventPriority.Low }), Event("Interview debrief", 3, 14, 0.5, "#7c3aed", new() { Notes = "Share feedback while it's fresh and decide on next steps.", Location = "Meeting room 1", Organizer = "Tom Becker", Attendees = 3, Priority = EventPriority.Medium }), Event("Hiring sync", 4, 11, 1, "#0369a1", new() { Notes = "Review the pipeline for the two open engineering roles.", Location = "Meeting room 2", Organizer = "People team", Attendees = 5, Priority = EventPriority.Medium }), Event("Retro", 4, 16, 1, "#4f46e5", new() { Notes = "What went well, what didn't, and one thing to try next sprint.", Location = "Meeting room 2", Organizer = "Marcus Lee", Attendees = 9, Priority = EventPriority.Medium }), AllDay("Release weekend", 5, 3, "#0369a1", new() { Notes = "Freeze on Friday night. Roll out on Saturday.", Organizer = "Release manager", Attendees = 14, Priority = EventPriority.High, IsOnline = true }), Event("Payroll run", 6, 9, 1, "#64748b", new() { Notes = "Runs automatically. Finance checks the totals afterwards.", Organizer = "Finance", Attendees = 2, Priority = EventPriority.Low, IsOnline = true }, readOnly: true), Event("Launch", -2, 9, 1, "#dc2626", new() { Notes = "Version 2.0 goes live. Support is on standby.", Organizer = "Release manager", Attendees = 30, Priority = EventPriority.High, IsOnline = true }), Event("Security training", -1, 14, 1.5, "#0891b2", new() { Notes = "Yearly refresher on phishing and password hygiene.", Location = "Main hall", Organizer = "IT security", Attendees = 60, Priority = EventPriority.Medium }), Event("Support handover", -1, 17, 0.5, "#16a34a", new() { Notes = "Pass open tickets to the evening rota.", Organizer = "Aisha Khan", Attendees = 4, Priority = EventPriority.Low, IsOnline = true }), AllDay("Planning offsite", -5, 2, "#7c3aed", new() { Notes = "Two days away from the desks to plan the year.", Location = "Lakeside lodge", Organizer = "Leadership team", Attendees = 18, Priority = EventPriority.High }), Event("Board meeting", 9, 10, 2, "#9333ea", new() { Notes = "Quarterly results and the hiring plan.", Location = "Boardroom", Organizer = "Leadership team", Attendees = 8, Priority = EventPriority.High }), Event("Roadmap review", 10, 14, 1, "#2563eb", new() { Notes = "Check the next two quarters against customer requests.", Location = "Meeting room 1", Organizer = "Priya Shah", Attendees = 10, Priority = EventPriority.Medium }), AllDay("Customer onsite", 12, 3, "#ea580c", new() { Notes = "The Hartley team visits for training and a product tour.", Location = "Head office", Organizer = "Aisha Khan", Attendees = 16, Priority = EventPriority.High }), ]; ``` ## Choosing which views to offer All three views are available by default. Pass `EnabledViews` an array of `TwCalendarView` values to offer only some of them. The switcher in the header only shows the views you list, always in the order Day, Week, Month. With a single view the switcher disappears, and the calendar just shows that view. If `View` isn't in the list, the first enabled view is shown instead. When the Day view is turned off, clicking a day in the Week or Month view only selects the date. This example offers just Week and Month. ```razor ``` ```csharp private DateTime enabledViewsSelectedDate = DateTime.Today; private TwCalendarView enabledViewsView = TwCalendarView.Week; private readonly TwCalendarView[] _enabledViews = [TwCalendarView.Week, TwCalendarView.Month]; ``` ## All-day and multi-day events An event that runs from midnight to midnight is an all-day event, and anything that lasts a day or longer is treated the same way. In the Day and Week views these sit in an "All day" strip above the time grid, like Microsoft Teams, so they don't cover the hours below. An event that covers several days is one bar across those days. In the Month view every event that covers more than one day is drawn as a bar across its days too, and it breaks at the end of each week and carries on in the next. An event that crosses midnight but lasts less than a day stays in the time grid and shows on both days. To make an event all day, turn on "All day" in the edit dialog, or set it to start and end at midnight yourself. The dialog then asks for dates instead of times, and the end date is the last day you want to cover. You can drag an all-day event onto another day, and it keeps its length. In the example below, "Company holiday", "Product conference" and "Release weekend" are all-day events. ```razor ``` ```csharp private DateTime allDaySelectedDate = DateTime.Today.AddDays(1); private TwCalendarView allDayView = TwCalendarView.Week; private List> allDaySchedules = BuildSampleSchedules(); ``` ## Adding & editing events Set `Editable` to get the "+" button in the header and let people open events in an edit dialog. Click an empty time slot to create an event there, or click an existing event to change it. An event with `ReadOnly` set always opens read-only, like "Lunch" and "Payroll run" below, even when `Editable` is on. Editable events can also be dragged. Move them between time slots (and between days in Week view), or between days in Month view, where the time of day stays the same. A dashed placeholder shows where the event will land, even over a slot that already has an event. The dialog's color picker sets `Schedule.Color`, which tints the event in every view. Leave it empty to use the theme color. ```razor ``` ```csharp private DateTime editableSelectedDate = DateTime.Today; private TwCalendarView editableView = TwCalendarView.Day; private List> editableSchedules = BuildSampleSchedules(); ``` ## Event details in the dialog Your own data lives in `Schedule.Value`. To show it in the dialog, pass `DialogProperties`: a dictionary that maps a property name on your type to the label you want. The read-only dialog lists each value that isn't empty. The edit dialog gives each property an editor that fits its type: a text field for strings, a number field for numbers, a switch for `bool`, a date and time picker for dates, and a select for enums. A property with no public setter shows as plain text. Names that don't match a property are skipped, and an empty label turns `OrderNumber` into "Order number". The properties appear in the order you list them, after Name, Start, End and Color. The dialog finds properties with reflection. Your type needs a public parameterless constructor so new events have something to edit, and the dialog works on a shallow copy of `Value`, so cancelling never changes the original. If you need something this can't express, such as a field that depends on another, use `EventDialogContent` to add your own markup. In this example, the empty label for `Priority` falls back to "Priority" and `Attendees` is relabeled "Guests". ```razor ``` ```csharp private DateTime detailsSelectedDate = DateTime.Today; private TwCalendarView detailsView = TwCalendarView.Day; private List> detailsSchedules = BuildSampleSchedules(); private readonly Dictionary _detailsDialogProperties = new() { [nameof(EventDetails.Notes)] = "Notes", [nameof(EventDetails.Location)] = "Location", [nameof(EventDetails.Attendees)] = "Guests", [nameof(EventDetails.Priority)] = "", [nameof(EventDetails.IsOnline)] = "Online meeting" }; ``` ## Custom event content Use `EventContentTemplate` to change how each event looks in all three views. ```razor @context.Name @context.DateTimeStart.ToString("h:mm tt") ``` ```csharp private DateTime customContentSelectedDate = DateTime.Today; private TwCalendarView customContentView = TwCalendarView.Week; ``` ## Search events `TwCalendar` has no search of its own. Set `OnSearch` and the header shows a search icon that calls your handler. This example opens a small dialog, built like any other `TwDialog` content, that filters `Schedules` by name. When you pick a result, it jumps to that event by setting `@bind-SelectedDate` and `@bind-View` on the calendar. ```razor ``` ```csharp private DateTime searchSelectedDate = DateTime.Today; private TwCalendarView searchView = TwCalendarView.Week; private async Task OnSearchAsync() { var reference = await DialogService.ShowAsync>("Search events", new TwDialogParameters { ["Schedules"] = _schedules }); var selected = await reference.GetReturnValueAsync>(); if (selected is not null) { searchSelectedDate = selected.DateTimeStart.Date; searchView = TwCalendarView.Day; } } ``` ## Keyboard navigation Each view is a grid with a single Tab stop for its days or time slots. Events are buttons reached with Tab. A read-only calendar has no time slots to focus, only its events. Dragging an event has a keyboard equivalent: open the event and change its start and end. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves between the toolbar buttons, the grid, and the events. | | `Arrow Left` or `Arrow Right` | Month view: moves to the previous or next day. Week view: moves to the same time on the previous or next day. The two keys swap in a right to left layout. | | `Arrow Up` or `Arrow Down` | Month view: moves to the same weekday in the previous or next week. Day and week view: moves to the previous or next time slot. | | `Home` or `End` | Month view: moves to the first or last day of the week. Day and week view: moves to the first or last time slot. | | `Enter` or `Space` | On a day: opens that day and moves focus to the calendar's title, which names it. On a time slot: starts a new event there. On an event: opens it. | | `Escape` | Closes the event dialog. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCalendar A Day/Week/Month schedule/agenda component. Composes `TwCalendarDayView`, `TwCalendarWeekView`, and `TwCalendarMonthView` for its three views, and owns opening the built-in `TwCalendarEventDialog` for creating/editing/viewing events. | Parameter | Type | Description | | --- | --- | --- | | `SelectedDate` | `DateTime` | The date driving the main view: the day shown in Day view, or the week/month containing it in Week/Month view. | | `SelectedDateChanged` | `EventCallback` | The bound `SelectedDate` value; invoked whenever navigation (Previous/Today/Next, or a day click in Week/Month view) moves it. | | `View` | `TwCalendarView` | The currently displayed view. | | `EnabledViews` | `IReadOnlyCollection?` | The views the user can switch between, shown as buttons in the header. `null` or empty (the default) enables all three. With one view enabled the switcher is hidden. If `View` isn't in the list, the calendar shows the first enabled view instead. | | `ViewChanged` | `EventCallback` | The bound `View` value; invoked whenever the view switcher, or a day click that drills into the Day view, changes it. | | `Schedules` | `List>` | The schedule entries shown across all three views. | | `SchedulesChanged` | `EventCallback>>` | The bound `Schedules` value; invoked whenever the built-in event dialog creates, edits, or deletes an entry. | | `OnEventCreated` | `EventCallback>` | Invoked with the new entry after the built-in dialog creates one. | | `OnEventUpdated` | `EventCallback>` | Invoked with the updated entry after the built-in dialog saves edits to an existing one. | | `OnEventDeleted` | `EventCallback>` | Invoked with the removed entry after the built-in dialog deletes it. | | `Editable` | `bool` | Global gate for editing: shows the header's "+" add button, opens the event dialog in edit mode (rather than read-only) for events that don't set their own `ReadOnly`, and lets events be dragged to reschedule them (see the Day/Week/Month view remarks on exactly what dragging does in each). | | `MaxHeight` | `string` | The CSS `max-height` (e.g. `"40rem"`, `"600px"`) of the Day/Week views' scrollable time grid. Not used by the Month view, which never scrolls. | | `ScrollToTime` | `TimeSpan` | The time of day the Day/Week views' time grid is scrolled to the first time it mounts (e.g. `TimeSpan.FromHours(8)` for 8am, the default). Only applied once per mount - navigating between dates while staying on the same view preserves whatever the user has since scrolled to, rather than resetting it on every date change. Not used by the Month view, which never scrolls. | | `OnSearch` | `EventCallback` | When set, shows a search icon button in the header that invokes this callback. No search logic lives in `TwCalendar` itself - the search UI (and navigating to a found event via `SelectedDate`/`View`) is left entirely to the caller, since what "search" means depends on the caller's own data and `T`. | | `EventContentTemplate` | `RenderFragment>?` | Optional custom rendering for an event's chip/block content across all three views; defaults to just `Name`. | | `DialogProperties` | `IReadOnlyDictionary?` | The properties of `Value` the event dialog shows, as property name to label. Each one appears as a labeled value in the read-only dialog and as an editor in the create/edit dialog, matched to the property's type: text, number, switch (`bool`), date and time picker, or select (enum). Properties without a public setter, or of any other type, show as read-only text. Names that don't match a public property are ignored. An empty label falls back to the property name split into words. Entries render in dictionary order. | | `EventDialogContent` | `RenderFragment>?` | Optional extra fields rendered inside the built-in create/edit dialog, after Name/Start/End/Color and any `DialogProperties` - for data the dialog can't generate an editor for on its own. The template's `context` is the dialog's working `Schedule` copy, whose `Value` is a shallow copy of the original, so mutating it in place is safe until Save. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwCalendarTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwCalendarTheme` by hand. --- # TwCard > TwCard is a Blazor card component for grouping content. Set Title, HeaderContent and Bordered, or lay cards out in a responsive grid. Documentation page: https://twblazor.com/card ## Basic card A simple card with a title and content. ```razor

Your account is in good standing. You have 3 active subscriptions.

``` ## Card without border Set `Bordered="false"` to remove the border. ```razor

This card relies on shadow and background contrast alone.

``` ## Card with footer Use `FooterContent` for actions or metadata. ```razor
Amount £2,340.00
Status Paid
Download View Details
``` ## Card with header content Use `HeaderContent` for custom header elements alongside the title. ```razor

Manage your team and their account permissions.

@foreach (var member in _members) {

@member.Name

@member.Role

}
``` ```csharp private sealed record TeamMember(string Name, string Role); private readonly TeamMember[] _members = [ new("Alice Johnson", "Admin"), new("Bob Smith", "Editor"), new("Carol Williams", "Viewer") ]; ``` ## Content-only card A card with no title - just content. ```razor

Jack Thompson

Product Designer

``` ## Card grid Cards work well in grid layouts. ```razor

£24,500

+12.5% from last month

1,234

+8.2% from last month

567

+3.1% from last month

``` ## Keyboard navigation This component is not interactive, so it has no keyboard controls of its own and is not a Tab stop. Anything interactive you place inside it keeps its own keyboard behaviour. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCard Represents a card component that provides a contained surface for grouping related content. | Parameter | Type | Description | | --- | --- | --- | | `Title` | `string?` | Gets or sets the title text displayed at the top of the card. | | `TitleLevel` | `int` | Gets or sets the heading level (1-6) rendered for `Title`, so the card's heading can fit correctly into the surrounding page's heading outline instead of always being an

regardless of context. Defaults to 3. | | `HeaderContent` | `RenderFragment?` | Gets or sets custom header content rendered below the title. | | `ChildContent` | `RenderFragment?` | Gets or sets the main content of the card. | | `Bordered` | `bool` | Gets or sets whether the card has a visible border. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwCardTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwCardTheme` by hand. --- # TwCarousel > TwCarousel is a Blazor carousel component. Bind SelectedIndex and configure AutoPlay, AutoPlayInterval, Loop, ShowArrows, ShowIndicators and swipe gestures. Documentation page: https://twblazor.com/carousel ## Basic carousel Use `TwCarousel` and `TwCarouselItem` to cycle through a set of slides. Only the active slide is rendered. ```razor
Slide 1
Slide 2
Slide 3
``` ## Images: object fit When a slide's content (e.g. an ``) doesn't match the carousel's aspect ratio, use Tailwind's `object-fit` utilities to control how it fills the slide's `h-full w-full` space. ```razor
@foreach (var fit in _objectFitOptions) { }
Placeholder 1 Placeholder 2 Placeholder 3 Placeholder 4 ``` ```csharp private static readonly (string Label, string Class)[] _objectFitOptions = [ ("Cover", "object-cover"), ("Contain", "object-contain"), ("Fill", "object-fill"), ("None", "object-none"), ("Scale Down", "object-scale-down"), ]; private string selectedObjectFit = "object-cover"; ``` ## Autoplay Set `AutoPlay` to automatically advance slides. A pause/play control is always shown so playback can be stopped, and it also pauses automatically while hovered or focused. ```razor
Slide 1
Slide 2
Slide 3
``` ## Indicator color Set `Color` to customize the active slide indicator's color. ```razor
Slide 1
Slide 2
Slide 3
``` ## Without arrows or indicators Set `ShowArrows` and `ShowIndicators` to `false` to rely on swipe gestures or programmatic navigation only. ```razor
Slide 1
Slide 2
``` ## Non-looping Set `Loop` to `false` to disable the arrow buttons at the first and last slide instead of wrapping around. ```razor
Slide 1
Slide 2
Slide 3
``` ## Bound selected index Bind `SelectedIndex` to control or observe the active slide from outside the carousel. ```razor

Selected slide: @(selectedIndex + 1)

Slide 1
Slide 2
Slide 3
``` ## Custom previous/next controls Set `LeftNavigation` and `RightNavigation` to render your own previous/next controls instead of the default arrow buttons. Each is a `RenderFragment`, so its `context` exposes the carousel's public API (`PreviousSlide`, `NextSlide`, `GoToSlide`, `ToggleAutoPlayPaused`, and more) for your own markup to call. ```razor Prev Next
Slide 1
Slide 2
Slide 3
``` ## Custom indicators Set `Indicators` to render your own slide-picker controls instead of the default dots. Its `context` exposes `SelectedIndex` and `GoToSlide` so your markup can both reflect and drive the active slide. ```razor
@for (var i = 0; i < 3; i++) { var index = i; @(index + 1) }
Slide 1
Slide 2
Slide 3
``` ## Keyboard navigation The arrow keys change slide from anywhere in the carousel, except while you are typing in a field or using a control inside a slide that needs them. An automatic slideshow pauses while the carousel has focus, and starts paused for anyone who has asked their system for reduced motion. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves through the pause button (when the slideshow plays automatically), the slide's own controls, the previous and next buttons, and the slide indicators. | | `Arrow Left` or `Arrow Right` | Shows the previous or next slide. The two keys swap in a right to left layout. | | `Enter` or `Space` | Presses the focused button: pause or play, previous, next, or a slide indicator. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCarousel Represents a carousel that displays one slide (`TwCarouselItem`) at a time, with optional arrow navigation, slide-picker indicators, swipe gestures, and automatic playback. | Parameter | Type | Description | | --- | --- | --- | | `SelectedIndex` | `int` | Gets or sets the index of the currently displayed slide. Supports two-way binding via `SelectedIndexChanged`. | | `SelectedIndexChanged` | `EventCallback` | Gets or sets the callback invoked whenever `SelectedIndex` changes, whether from the arrow buttons, an indicator, a keyboard press, a swipe gesture, or automatic playback. | | `ShowArrows` | `bool` | Gets or sets whether the previous/next arrow buttons are displayed. Default is `true`. | | `ShowIndicators` | `bool` | Gets or sets whether the slide-picker indicator dots are displayed below the carousel. Default is `true`. | | `EnableSwipeGesture` | `bool` | Gets or sets whether a horizontal touch swipe switches between slides. Default is `true`. | | `AutoPlay` | `bool` | Gets or sets whether the carousel automatically advances to the next slide on a timer. A visible pause/play toggle is rendered whenever this is enabled, so playback can always be stopped (WCAG 2.2.2), and playback also pauses automatically while the pointer or keyboard focus is within the carousel. Default is `false`. | | `AutoPlayInterval` | `TimeSpan` | Gets or sets the delay between automatic slide changes when `AutoPlay` is enabled. Default is 5 seconds. | | `Loop` | `bool` | Gets or sets whether navigating past the last slide wraps around to the first (and vice versa). When `false`, the arrow buttons are disabled at the boundaries instead. Default is `true`. | | `Color` | `Color?` | Gets or sets the accent color used for the active slide indicator dot. If `null`, the theme's default indicator color is used. | | `ButtonColor` | `Color` | Gets or sets the color used for the previous/next arrow buttons and the play/pause toggle. Passed straight through to the underlying `TwButton` (via `TwIcon`) as a filled variant, so it needs no bespoke background classes of its own. Default is `Light`. | | `ChildContent` | `RenderFragment` | Gets or sets the `TwCarouselItem` children that make up the carousel's slides. | | `LeftNavigation` | `RenderFragment?` | Gets or sets custom content to render in place of the default previous-slide arrow button. The render fragment's context is this `TwCarousel` instance, giving access to its public API (e.g. `PreviousSlide`, `NextSlide`, `GoToSlide`, `ToggleAutoPlayPaused`, `IsAutoPlayPaused`) so custom controls can drive the carousel. When `null` (default), the built-in previous arrow is rendered instead, subject to `ShowArrows`. | | `RightNavigation` | `RenderFragment?` | Gets or sets custom content to render in place of the default next-slide arrow button. See `LeftNavigation` for details on the render fragment's context and fallback behavior. | | `Indicators` | `RenderFragment?` | Gets or sets custom content to render in place of the default slide-picker indicator dots. The render fragment's context is this `TwCarousel` instance, giving access to its public API (e.g. `GoToSlide`, `SelectedIndex`) so custom indicators can drive the carousel. When `null` (default), the built-in indicator dots are rendered instead, subject to `ShowIndicators`. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwCarouselItem Represents a single slide within a `TwCarousel`. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment` | The content to display while this slide is active. This is a required parameter. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwCarouselTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwCarouselTheme` by hand. --- # TwChart > TwChart is the Blazor chart container for over fifty chart types. It adds a title, loading state and shared options. Accessible and script-free. Documentation page: https://twblazor.com/chart ## Basic usage `TwChart` is the container: it frames a chart with a title, a description and a loading state. Place one chart component inside it and pass the data. Every chart supplies its own legend, tooltips on hover and keyboard focus, and a table view of the same data. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "East", "West"]; private readonly ChartSeries[] _revenue = [new("Revenue", [420, 310, 275, 380])]; private readonly ChartSeries[] _yearly = [ new("2024", [360, 290, 240, 330]), new("2025", [420, 310, 275, 380]) ]; ``` ## Choosing a chart Start from what the reader needs to see, then pick the chart. Each chart has its own page with examples of every option. ## Title and description `Title` names the chart, on screen and for assistive technology. Use `Description` for the unit or the period, so the axis does not have to carry it. Both are optional; without a title, give the chart an `AriaLabel`. ```razor ``` ## Height `Height` sets how tall the plot is: `ChartHeight.Small`, `Medium` (the default) or `Large`. Set it on the container, or on a chart to override the container. The width always follows the space available. Radial charts are square, and `Height` sets how wide the square may grow. ```razor ``` ## Formatting values Every chart takes `ValueFormat`, any .NET numeric format string, or `ValueFormatter`, a function, for full control. The format applies to the axis, tooltips, value labels and table view alike, in the current culture. ```razor ``` ```razor ``` ```csharp private static string FormatThousands(double value) => $"£{value:0}k"; ``` ## Legend A chart with two or more series shows a legend; a single series needs none, because the title names it. Each entry is a button that hides or shows its series, and a series keeps its color while others are hidden. Set `InteractiveLegend` to `false` for a plain legend, or `ShowLegend` to `false` to remove it. ```razor ``` ## Table view "View as table" swaps the plot for a table of the same data, and "View as chart" swaps it back. The table is the accessible alternative to the plot, so only set `ShowTableToggle` to `false` when the same data is available elsewhere on the page. `TableViewLabel`, `ChartViewLabel` and `TableLabel` change the wording. ```razor ``` ## Loading and empty states Set `Loading` on the container to show a placeholder of the right height while data is fetched. A chart with no data shows its `EmptyText` instead of an empty set of axes. ```razor
``` ## Accessibility The chart is a group named by the container's `Title`. Each data point is announced with its values. The plot is a single tab stop: tab into it, then use the arrow, `Home` and `End` keys to move between data points. On a touch screen, tap a data point to show its tooltip. A slice, wedge, ring, ribbon, tile or filled curve responds anywhere on its shape. Focus shows the same tooltip as hover, and `Esc` dismisses it. The table view presents the same data without the plot. Text never takes a series color, direction and status are always named as well as colored, and colors are assigned in a fixed order chosen so neighboring series stay distinguishable for color-blind readers. Keep to eight series or fewer: there are eight colors, and a ninth series would reuse the last. ## Adding your own chart type Every chart is a small class that describes what to draw. Derive from `TwCategoryChartBase` (categories and series), `TwValueChartBase` (labelled values) or `TwChartBase`, and add marks with the `ChartSceneBuilder`. Positions are percentages of the plot area. The legend, tooltips, keyboard support, table view and theming come from the base class, so a new chart needs no markup or styles of its own. ```csharp /// /// A custom chart: each value is drawn as a filled track out of 100. /// public class CompletionChart : TwValueChartBase { protected override void BuildMarks(ChartSceneBuilder builder) { builder.Horizontal = true; var band = new ChartBand(Data.Count); var color = ChartColor.Series(0); builder.BandAxis([.. Data.Select(item => item.Label)], band); for (var i = 0; i < Data.Count; i++) { var filled = Math.Clamp(Data[i].Value, 0, 100); builder.Bar(band.Center(i), 6, 0, 100, ChartColor.Track, ChartCorner.All, gap: false); builder.Bar(band.Center(i), 6, 0, filled, color, ChartCorner.All, gap: false); builder.BandDatum(band.Center(i), band.Step, Data[i].Label, [new ChartDatumRow(effectiveValueHeader, FormatValue(Data[i].Value), color)]); } } } ``` ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwChart The container for a chart: it frames any chart component (such as `TwBarChart` or `TwLineChart`) with a title, a description and a loading state. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the chart to display, for example a `TwColumnChart`. | | `Title` | `string?` | Gets or sets the title shown above the chart. It also names the chart for assistive technology. | | `Description` | `string?` | Gets or sets a short description shown under the title, for example the unit or the period covered. | | `Height` | `ChartHeight` | Gets or sets the height of the plot area for the charts inside the container. | | `Loading` | `bool` | Gets or sets whether the data is still loading. A placeholder is shown in place of the chart. | | `LoadingLabel` | `string?` | Gets or sets the text announced by assistive technology while `Loading` is set. Defaults to the localized `Chart_Loading` text ("Loading chart"). | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwChartTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwChartTheme` by hand. --- # TwArcDiagramChart > TwArcDiagramChart is a Blazor arc diagram: nodes set out along a line and joined by an arc for every link. Documentation page: https://twblazor.com/chart/arc-diagram ## Basic usage `TwArcDiagramChart` sets `ChartGraphNode` values out along a line in the order given and draws an arc above it for every `ChartGraphLink`. The further apart two linked nodes are, the higher their arc. Links refer to nodes by `Id`. ```razor ``` ```csharp private readonly ChartGraphNode[] _topics = [new("a", "Layout"), new("b", "Color"), new("c", "Type"), new("d", "Motion")]; private readonly ChartGraphLink[] _related = [new("a", "b", 2), new("a", "c", 1), new("b", "c", 3), new("a", "d", 1)]; ``` ## Order reveals structure The order of the nodes is the design. With the members of each group listed together, links inside a group are short low arcs and the few links between groups rise above them. ```razor ``` ```csharp private readonly ChartGraphNode[] _engineers = [ new("ana", "Ana"), new("bo", "Bo"), new("cy", "Cy"), new("di", "Di"), new("eli", "Eli"), new("fay", "Fay"), new("gus", "Gus"), new("hal", "Hal") ]; private readonly ChartGraphLink[] _reviews = [ new("ana", "bo", 14), new("bo", "cy", 9), new("cy", "di", 11), new("ana", "cy", 6), new("bo", "di", 4), new("eli", "fay", 12), new("fay", "gus", 8), new("gus", "hal", 10), new("eli", "gus", 5), new("di", "eli", 3), new("ana", "hal", 1) ]; ``` ## A sequence When the nodes have a natural order, such as chapters or stops on a route, arcs show what jumps ahead and what calls back. ```razor ``` ```csharp private readonly ChartGraphNode[] _chapters = [ new("1", "Ch. 1"), new("2", "Ch. 2"), new("3", "Ch. 3"), new("4", "Ch. 4"), new("5", "Ch. 5"), new("6", "Ch. 6") ]; private readonly ChartGraphLink[] _references = [new("1", "2"), new("2", "3"), new("1", "5"), new("3", "4"), new("4", "6"), new("2", "6")]; ``` ## When to use Use an arc diagram when the order of the nodes matters, or to show clusters as runs of short arcs. Links that name a missing node, or join a node to itself, are left out. To show how much flows along each link, use [TwChordDiagramChart](https://twblazor.com/chart/chord-diagram.md). ## Summary Tooltips and the table view give the source, target and value of each link. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwArcDiagramChart An arc diagram: nodes set out along a line in the order given, with an arc above the line for every link, the arc reaching higher the further apart its two nodes are. | Parameter | Type | Description | | --- | --- | --- | | `Nodes` | `IReadOnlyList` | Gets or sets the nodes. Each needs a unique `Id`; repeats are left out. | | `Links` | `IReadOnlyList` | Gets or sets the links between nodes, by node identifier. Links that name a missing node, or join a node to itself, are left out. | | `SourceHeader` | `string?` | Gets or sets the heading of the column naming where each link starts in the table view. Defaults to the localized `Chart_Source` text ("Source"). | | `TargetHeader` | `string?` | Gets or sets the heading of the column naming where each link ends in the table view. Defaults to the localized `Chart_Destination` text ("Target"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels a link's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwAreaChart > TwAreaChart is a Blazor area chart: a line chart with the space beneath filled. Supports stacked areas and smooth or stepped curves. Documentation page: https://twblazor.com/chart/area ## Basic usage `TwAreaChart` is a line chart with the space under each line filled with a light wash, which emphasises volume. The scale always includes zero so the filled area stays honest. ```razor ``` ```csharp private readonly string[] _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; private readonly ChartSeries[] _organic = [new("Organic", [42, 48, 55, 61, 58, 70])]; ``` ## Stacked Set `Stacked` to pile the series on top of each other, showing how they add up to a total over time. Missing and negative values count as zero when stacked. ```razor ``` ```csharp private readonly ChartSeries[] _visitors = [ new("Organic", [42, 48, 55, 61, 58, 70]), new("Paid", [30, 34, 31, 45, 52, 49]), new("Referral", [12, 15, 21, 19, 26, 33]) ]; ``` ## Curves `Curve` works as it does on a line chart: `ChartCurve.Smooth` for a spline area and `ChartCurve.Step` for a stepped one. ```razor ``` ## Overlapping series Without stacking, the washes overlap so every line stays visible. Past two or three series, stack them or use [TwSmallMultiplesChart](https://twblazor.com/chart/small-multiples.md) instead. ```razor ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwAreaChart An area chart: a line chart with the space under each line filled, emphasising volume. Set `Stacked` to show how the series add up to a total. | Parameter | Type | Description | | --- | --- | --- | | `Stacked` | `bool` | Gets or sets whether the series are stacked on top of each other (a stacked area chart). | | `Curve` | `ChartCurve` | Gets or sets how points are joined: straight (line), smooth (spline) or stepped (step line). | | `ShowMarkers` | `bool?` | Gets or sets whether a dot is drawn at every point. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBarChart > TwBarChart is a Blazor bar chart that compares categories with horizontal bars. Supports grouped, stacked, 100% stacked and diverging layouts. Documentation page: https://twblazor.com/chart/bar ## Basic usage `TwBarChart` draws horizontal bars whose length shows the value of each category. Bars suit long category labels and long lists, because the labels read left to right beside each bar. Pass the category labels as `Categories` and one or more `ChartSeries` as `Series`. For the other direction use [TwColumnChart](https://twblazor.com/chart/column.md); the parameters are identical. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "East", "West"]; private readonly ChartSeries[] _revenue = [new("Revenue", [420, 310, 275, 380])]; private readonly ChartSeries[] _yearly = [ new("2024", [360, 290, 240, 330]), new("2025", [420, 310, 275, 380]) ]; ``` ## Value labels Set `ShowValues` to label each bar with its value. It works best with few bars; with many, the axis and tooltips carry the values more cleanly. ```razor ``` ## Grouped Pass more than one series and each category shows its series side by side. A legend appears automatically, and clicking an entry hides that series. ```razor ``` ## Stacked Set `Stacking` to `ChartStacking.Stacked` to pile the series on top of each other, so each bar shows the category total as well as its parts. ```razor ``` ## 100% stacked `ChartStacking.Percent` scales every bar to the same length, so the chart compares shares instead of totals. Tooltips and the table view still show the original values. ```razor ``` ## Diverging Negative values grow the other way from the baseline. Stack a positive and a negative series to make a diverging chart, for example agreement against disagreement. ```razor ``` ```csharp private readonly string[] _teams = ["Design", "Engineering", "Sales", "Support"]; private readonly ChartSeries[] _sentiment = [ new("Agree", [62, 48, 35, 54]), new("Disagree", [-18, -30, -41, -22]) ]; ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBarChart A bar chart: horizontal bars whose length shows the value of each category. With several series it becomes a grouped, stacked or 100% stacked bar chart, see `Stacking`. | Parameter | Type | Description | | --- | --- | --- | | `Stacking` | `ChartStacking` | Gets or sets how multiple series share a category: side by side, stacked, or stacked to 100%. | | `ShowValues` | `bool` | Gets or sets whether each bar is labelled with its value. Ignored when `Stacking` is on. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBarcodeChart > TwBarcodeChart is a Blazor barcode chart that draws a thin line for every raw observation along one axis, so clusters and gaps stand out. Documentation page: https://twblazor.com/chart/barcode ## Basic usage `TwBarcodeChart` draws a thin vertical line for every value in `Values` along a single horizontal axis. Clusters show as dense stripes and gaps as white space, without the values being grouped into ranges first. ```razor ``` ```csharp private readonly double[] _responseTimes = [112, 118, 121, 123, 127, 131, 135, 138, 142, 144, 149, 151, 153, 168, 190, 245, 290]; ``` ## Clusters and gaps Two tight groups with nothing between them is a pattern a histogram can blur if a bin happens to straddle the gap. On a barcode chart it is unmistakable. ```razor ``` ```csharp private readonly double[] _eruptions = [ 1.7, 1.8, 1.8, 1.9, 1.9, 2.0, 2.0, 2.1, 2.2, 2.3, 2.4, 3.6, 3.8, 3.9, 4.0, 4.1, 4.1, 4.2, 4.3, 4.3, 4.4, 4.5, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0 ]; ``` ## Repeated values Values that repeat share one line, and its tooltip and table row give how many observations it stands for. Use `ValueLabel` and `CountLabel` to name the two columns. ```razor ``` ```csharp private readonly double[] _orderSizes = [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 8, 12, 12, 24]; ``` ## When to use A barcode chart suits a few dozen to a few hundred observations. Beyond that the lines merge, and [TwHistogramChart](https://twblazor.com/chart/histogram.md) or [TwDensityPlotChart](https://twblazor.com/chart/density-plot.md) is the better choice. ## Summary Tooltips and the table view give each value and the count of observations that share it. The arrow keys step through the values from lowest to highest. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBarcodeChart A barcode chart: a thin line for every observation along a single value axis, so clusters show as dense stripes and gaps as white space. | Parameter | Type | Description | | --- | --- | --- | | `Values` | `IReadOnlyList` | Gets or sets the raw observations to plot. | | `ValueLabel` | `string?` | Gets or sets the label for an observation's value in the table view. Defaults to the localized `Chart_Value` text ("Value"). | | `CountLabel` | `string?` | Gets or sets the label for how many observations share a value in tooltips and the table view. Defaults to the localized `Chart_Count` text ("Count"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBeeswarmChart > TwBeeswarmChart is a Blazor beeswarm chart that draws every observation as a dot, nudged sideways so none overlap. Documentation page: https://twblazor.com/chart/beeswarm ## Basic usage `TwBeeswarmChart` draws every value in a `ChartSample` as a dot along the value axis and moves each one sideways just far enough to clear its neighbors. The swarm widens where values cluster, so you see both the spread and how many values sit at each level. ```razor ``` ```csharp private readonly ChartSample[] _plans = [ new("Free", [3, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9]), new("Team", [5, 6, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10]), new("Enterprise", [6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10]) ]; ``` ## Clusters and outliers Because no dot is hidden behind another, repeated values and stragglers are both easy to spot. Here most builds finish in about four minutes, with a handful of slow ones on the main branch. ```razor ``` ```csharp private readonly ChartSample[] _builds = [ new("main", [3.8, 3.9, 4.0, 4.0, 4.1, 4.1, 4.1, 4.2, 4.2, 4.3, 4.3, 4.4, 4.6, 7.9, 8.4, 11.2]), new("release", [4.4, 4.5, 4.6, 4.6, 4.7, 4.8, 4.8, 4.9, 5.0, 5.2]), new("feature", [2.9, 3.1, 3.3, 3.4, 3.6, 3.7, 3.9, 4.0, 4.4, 4.9, 5.5, 6.1]) ]; ``` ## Horizontal Set `Horizontal` to list the groups down the side with values running left to right. ```razor ``` ## When to use A beeswarm suits tens of values per group. A cluster too large for its group's slot overlaps at the edges, so for hundreds of values prefer [TwViolinPlotChart](https://twblazor.com/chart/violin-plot.md) or [TwBoxPlotChart](https://twblazor.com/chart/box-plot.md). ## Summary Tooltips and the table view give the count, minimum, lower quartile, median, upper quartile and maximum of each group. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBeeswarmChart A beeswarm chart: every observation drawn as a dot along the value axis, nudged sideways just far enough that no two dots overlap, so both the spread and the number of values at each level are visible. | Parameter | Type | Description | | --- | --- | --- | | `Samples` | `IReadOnlyList` | Gets or sets the groups of raw observations to plot. | | `Horizontal` | `bool` | Gets or sets whether groups are listed top to bottom with values running left to right. | | `LabelHeader` | `string?` | Gets or sets the heading of the group column in the table view. Defaults to the localized `Chart_Group` text ("Group"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBoxPlotChart > TwBoxPlotChart is a Blazor box plot that summarises groups of raw values by median, quartiles, whiskers and outliers. Documentation page: https://twblazor.com/chart/box-plot ## Basic usage `TwBoxPlotChart` summarises each `ChartSample` of raw observations. The box spans the middle half of the values with a line at the median. Whiskers reach the furthest values within 1.5 times the length of the box, and anything beyond is drawn as an outlier dot. ```razor ``` ```csharp private readonly ChartSample[] _services = [ new("Search", [112, 120, 131, 135, 138, 142, 144, 149, 151, 153, 290]), new("Checkout", [156, 158, 160, 163, 167, 170, 172, 176, 181, 185]), new("Reports", [190, 196, 204, 215, 228, 240, 262, 150, 310]) ]; ``` ## Horizontal Set `Horizontal` to list the groups down the side, which suits long labels and many groups. ```razor ``` ## Summary Tooltips and the table view give the count, minimum, lower quartile, median, upper quartile and maximum of each group. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBoxPlotChart A box plot: for each group, a box spanning the middle half of the values with a line at the median, whiskers reaching to the furthest values within 1.5 times the box's length, and dots for outliers beyond them. | Parameter | Type | Description | | --- | --- | --- | | `Samples` | `IReadOnlyList` | Gets or sets the groups of raw observations to plot. | | `Horizontal` | `bool` | Gets or sets whether groups are listed top to bottom with values running left to right. | | `LabelHeader` | `string?` | Gets or sets the heading of the group column in the table view. Defaults to the localized `Chart_Group` text ("Group"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBulletChart > TwBulletChart is a Blazor bullet chart that benchmarks an actual value against a target, with shaded bands for qualitative ranges. Documentation page: https://twblazor.com/chart/bullet ## Basic usage `TwBulletChart` shows, for each measure, a bar for the actual value and a marker for the target. Pass a list of `ChartBullet` with a label, a value and a target. Each measure has its own scale, so revenue in thousands and a percentage can share one chart. ```razor ``` ```csharp private readonly ChartBullet[] _targets = [ new("Revenue", 270, 250), new("Profit", 22, 26), new("New customers", 1650, 1500) ]; ``` ## Qualitative ranges Give a bullet a list of `Ranges` to shade bands behind the bar, for example the limits of poor, fair and good. The darkest band is the lowest range. ```razor ``` ```csharp private readonly ChartBullet[] _bullets = [ new("Revenue", 270, 250, [150, 225, 300]), new("Profit", 22, 26, [15, 22, 30]), new("New customers", 1650, 1500, [1000, 1400, 2000]) ]; ``` ## Labels `ValueLabel` and `TargetLabel` rename the two values in the legend, tooltips and table view. ```razor ``` ## Summary Tooltips and the table view give the actual value and the target of each measure. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBulletChart A bullet chart: for each measure, a bar showing the actual value, a marker showing the target and optional shaded bands for qualitative ranges such as poor, fair and good. | Parameter | Type | Description | | --- | --- | --- | | `Items` | `IReadOnlyList` | Gets or sets the measures to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Measure` text ("Measure"). | | `ValueLabel` | `string?` | Gets or sets the label for the actual value. Defaults to the localized `Chart_Actual` text ("Actual"). | | `TargetLabel` | `string?` | Gets or sets the label for the target value. Defaults to the localized `Chart_Target` text ("Target"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBumpAreaChart > TwBumpAreaChart is a Blazor bump area chart: a band per series that is as thick as its value and moves as its rank changes. Documentation page: https://twblazor.com/chart/bump-area ## Basic usage `TwBumpAreaChart` draws a band for each series. At every category the bands are stacked from the largest value at the top to the smallest at the bottom, so a band climbs when its series overtakes another and its thickness shows by how much it leads. ```razor ``` ```csharp private readonly string[] _years = ["2021", "2022", "2023", "2024", "2025"]; private readonly ChartSeries[] _platforms = [ new("Atlas", [42, 38, 33, 30, 26]), new("Beacon", [30, 32, 36, 39, 44]), new("Comet", [28, 30, 31, 31, 30]) ]; ``` ## Changing leaders With more series and more crossings the chart tells the story of a race. Where a [TwBumpChart](https://twblazor.com/chart/bump.md) shows only the order, the band thickness here also shows when the leader was far ahead and when the field was close. ```razor ``` ```csharp private readonly string[] _quarters = ["Q1 23", "Q2 23", "Q3 23", "Q4 23", "Q1 24", "Q2 24", "Q3 24", "Q4 24"]; private readonly ChartSeries[] _browsers = [ new("Falcon", [38, 36, 33, 30, 27, 25, 22, 20]), new("Otter", [24, 26, 29, 32, 35, 37, 40, 43]), new("Lynx", [20, 19, 19, 18, 17, 17, 16, 15]), new("Heron", [12, 13, 12, 13, 14, 13, 14, 13]), new("Wren", [6, 6, 7, 7, 7, 8, 8, 9]) ]; ``` ## Late arrivals Use `null` where a series has no value. Its band starts, stops or breaks there, and the other bands close the gap. ```razor ``` ```csharp private readonly ChartSeries[] _products = [ new("Hardware", [4.2, 4.0, 3.6, 3.1, 2.8]), new("Software", [2.1, 2.9, 3.8, 4.6, 5.2]), new("Services", [null, null, 0.9, 1.8, 3.4]) ]; ``` ## When to use Use a bump area chart when both the order of the series and the size of the lead matter. When only the order matters, [TwBumpChart](https://twblazor.com/chart/bump.md) is simpler. Negative values count as zero. ## Summary Tooltips and the table view give the value of every series for each category. Tooltips also give the rank of each series. The arrow keys move down each category in rank order, then on to the next. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBumpAreaChart A bump area chart: a band for each series that is as thick as its value and moves up or down as its rank among the series changes, showing both who leads and by how much. | Parameter | Type | Description | | --- | --- | --- | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwBumpChart > TwBumpChart is a Blazor bump chart that tracks how series rank against each other across categories, with the highest value ranked first. Documentation page: https://twblazor.com/chart/bump ## Basic usage `TwBumpChart` plots rank instead of value: in each category the series with the highest value is ranked first. Lines cross where one series overtakes another. Each line is labelled at its end, and tooltips give both the rank and the value. ```razor ``` ```csharp private readonly string[] _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; private readonly ChartSeries[] _visitors = [ new("Organic", [42, 48, 30, 61, 58, 70]), new("Paid", [30, 34, 51, 45, 62, 49]), new("Referral", [12, 40, 41, 19, 26, 55]) ]; ``` ## Labels `RankLabel` renames the rank in tooltips. ```razor ``` ## When to use A bump chart hides how far apart the values are. When the size of the lead matters, use [TwLineChart](https://twblazor.com/chart/line.md). ## Summary Tooltips and the table view give the value of every series for each category. Tooltips also give the rank of each series. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwBumpChart A bump chart: lines that track how each series ranks against the others across the categories. The highest value in a category ranks first. | Parameter | Type | Description | | --- | --- | --- | | `RankLabel` | `string?` | Gets or sets the label for the rank in tooltips. Defaults to the localized `Chart_Rank` text ("Rank"). | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwCandlestickChart > TwCandlestickChart is a Blazor candlestick chart showing the open, high, low and close of each period. Also draws OHLC charts. Documentation page: https://twblazor.com/chart/candlestick ## Basic usage `TwCandlestickChart` draws, for each `ChartOhlc` period, a body between the open and the close and a wick reaching the high and the low. Rising and falling periods differ by color, and the legend and tooltips name the direction. ```razor ``` ```csharp private readonly ChartOhlc[] _prices = [ new("Jan 02", 102.00, 103.76, 101.42, 103.40), new("Jan 03", 104.68, 105.31, 102.88, 104.80), new("Jan 06", 104.80, 105.27, 102.54, 103.10), new("Jan 07", 103.10, 106.24, 102.76, 105.60), new("Jan 08", 101.90, 109.20, 101.20, 107.20), new("Jan 09", 107.20, 107.91, 104.48, 105.30), new("Jan 10", 105.95, 107.30, 103.70, 106.10), new("Jan 13", 106.10, 109.23, 105.72, 108.40), new("Jan 14", 108.40, 109.08, 106.12, 107.00), new("Jan 15", 108.00, 108.80, 101.50, 104.10), new("Jan 16", 104.10, 104.87, 101.98, 102.80), new("Jan 17", 102.80, 104.23, 102.16, 103.70), new("Jan 20", 103.70, 104.08, 100.94, 101.90), new("Jan 21", 104.80, 105.60, 98.10, 99.50), new("Jan 22", 99.50, 101.16, 98.91, 100.70), new("Jan 23", 100.70, 101.24, 97.36, 98.20), new("Jan 24", 98.20, 98.63, 95.71, 96.40), new("Jan 27", 96.40, 103.90, 94.10, 98.60), new("Jan 28", 98.60, 99.03, 94.62, 95.70), new("Jan 29", 95.70, 96.12, 92.34, 93.10), new("Jan 30", 94.65, 96.30, 90.70, 94.80), new("Jan 31", 94.80, 95.04, 91.63, 92.40), new("Feb 03", 92.40, 98.80, 87.90, 95.60), new("Feb 04", 95.60, 98.91, 95.18, 98.30), new("Feb 05", 98.30, 98.76, 96.21, 96.90), new("Feb 06", 93.20, 101.50, 92.60, 99.70), new("Feb 07", 99.70, 103.18, 99.12, 102.50), new("Feb 10", 105.80, 106.50, 98.10, 100.20), new("Feb 11", 100.20, 100.63, 96.84, 97.60), new("Feb 12", 99.02, 101.40, 95.70, 99.10), new("Feb 13", 99.10, 102.74, 98.67, 101.80), new("Feb 14", 101.80, 105.28, 101.31, 104.60), new("Feb 17", 104.60, 105.13, 101.74, 102.70), new("Feb 18", 102.70, 106.02, 102.18, 105.30), new("Feb 19", 100.80, 109.40, 99.30, 107.90), new("Feb 20", 107.90, 108.31, 104.38, 105.20), new("Feb 21", 108.40, 109.10, 99.20, 102.60), new("Feb 24", 102.60, 103.02, 99.61, 100.40), new("Feb 25", 100.40, 101.18, 97.83, 98.70), new("Feb 26", 98.70, 103.00, 91.10, 96.10), new("Feb 27", 96.10, 99.06, 95.77, 98.40), new("Feb 28", 98.40, 102.13, 98.02, 101.20), new("Mar 03", 99.35, 106.10, 97.10, 99.30), new("Mar 04", 99.30, 103.17, 98.85, 102.50), new("Mar 05", 102.50, 106.24, 101.93, 105.60), new("Mar 06", 105.60, 109.08, 105.14, 108.20), new("Mar 07", 108.20, 108.74, 104.86, 106.30), new("Mar 10", 101.90, 112.50, 101.20, 109.70), new("Mar 11", 109.70, 113.28, 109.21, 112.40), new("Mar 12", 113.80, 114.50, 106.40, 110.10), new("Mar 13", 110.10, 110.72, 106.24, 107.60), new("Mar 14", 107.60, 108.13, 103.48, 104.80), new("Mar 17", 108.70, 109.40, 100.20, 102.90), new("Mar 18", 102.90, 106.18, 102.37, 105.70), new("Mar 19", 105.70, 109.27, 105.16, 108.60), new("Mar 20", 106.85, 112.20, 104.10, 106.80), new("Mar 21", 106.80, 110.83, 106.31, 110.20), new("Mar 24", 110.20, 117.00, 107.00, 113.10), new("Mar 25", 113.10, 113.58, 109.84, 111.40), new("Mar 26", 111.40, 115.73, 110.96, 115.20) ]; ``` ## OHLC Set `Kind` to `CandlestickStyle.Ohlc` to draw a tick for the open on the left and the close on the right instead of a body. ```razor ``` ## Labels and format `RisingLabel` and `FallingLabel` rename the directions, and `ValueFormat` formats the prices. ```razor ``` ## Summary Tooltips and the table view give the open, high, low and close of each period. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCandlestickChart A candlestick chart: for each period, a body between the opening and closing value and a wick reaching the high and the low. Set `Kind` to `Ohlc` for an OHLC chart. | Parameter | Type | Description | | --- | --- | --- | | `Items` | `IReadOnlyList` | Gets or sets the periods to plot, in order. | | `Kind` | `CandlestickStyle` | Gets or sets whether each period is drawn as a candle or as open and close ticks. | | `RisingLabel` | `string?` | Gets or sets the legend label for a period that closed at or above its open. Defaults to the localized `Chart_Rising` text ("Rising"). | | `FallingLabel` | `string?` | Gets or sets the legend label for a period that closed below its open. Defaults to the localized `Chart_Falling` text ("Falling"). | | `LabelHeader` | `string?` | Gets or sets the heading of the period column in the table view. Defaults to the localized `Chart_Period` text ("Period"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwCategoricalScatterChart > TwCategoricalScatterChart is a Blazor chart that places a dot where two categories meet and sizes it by a value. Documentation page: https://twblazor.com/chart/categorical-scatter ## Basic usage `TwCategoricalScatterChart` places a dot where a horizontal category meets a vertical one and sizes it by a value. Each `ChartCategoricalPoint` names its two categories, so you only list the combinations that exist. ```razor ``` ```csharp private readonly ChartCategoricalPoint[] _responses = [ new("Service", "Positive", 48), new("Price", "Positive", 12), new("Quality", "Positive", 62), new("Service", "Neutral", 15), new("Price", "Neutral", 20), new("Quality", "Neutral", 9), new("Service", "Negative", 7), new("Price", "Negative", 34) ]; ``` ## Sparse combinations The chart is most useful when many combinations are empty, where a heatmap would be mostly blank cells. Categories appear in the order they are first used, so list the points in the order you want the axes to read. ```razor ``` ```csharp private readonly ChartCategoricalPoint[] _incidents = [ new("Payments", "Critical", 2), new("Search", "Critical", 1), new("Payments", "High", 5), new("Accounts", "High", 3), new("Mobile", "High", 8), new("Search", "Medium", 11), new("Mobile", "Medium", 14), new("Reports", "Medium", 4), new("Payments", "Low", 9), new("Accounts", "Low", 17), new("Search", "Low", 6), new("Reports", "Low", 21) ]; ``` ## Named points Give a point a `Label` to title its tooltip and add a label column to the table view. ```razor ``` ```csharp private readonly ChartCategoricalPoint[] _talks = [ new("Monday", "Design", 180, "Design systems at scale"), new("Monday", "Engineering", 420, "Keynote: ten years of Blazor"), new("Tuesday", "Design", 95, "Color for everyone"), new("Tuesday", "Engineering", 260, "Rendering without script"), new("Tuesday", "Product", 140, "Roadmaps that survive"), new("Wednesday", "Product", 210, "Pricing experiments") ]; ``` ## When to use Use a categorical scatter plot when most combinations of the two categories are empty. The area of a dot, not its diameter, follows the value. For a full grid of values use [TwMatrixChart](https://twblazor.com/chart/matrix.md) or [TwHeatmapChart](https://twblazor.com/chart/heatmap.md). ## Summary Tooltips and the table view give the two categories and the value of each point. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCategoricalScatterChart A categorical scatter plot: a dot where a horizontal category meets a vertical one, sized by its value, for showing how a measure varies across two sets of categories when most combinations are empty. | Parameter | Type | Description | | --- | --- | --- | | `Points` | `IReadOnlyList` | Gets or sets the points to plot. | | `XTitle` | `string` | Gets or sets the title of the horizontal axis. It also labels the horizontal category in tooltips and the table view. | | `YTitle` | `string` | Gets or sets the title of the vertical axis. It also labels the vertical category in tooltips and the table view. | | `ValueTitle` | `string?` | Gets or sets the label for a point's value in tooltips and the table view. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwChordDiagramChart > TwChordDiagramChart is a Blazor chord diagram: nodes as arcs around a circle joined by ribbons as thick as the flow between them. Documentation page: https://twblazor.com/chart/chord-diagram ## Basic usage `TwChordDiagramChart` arranges `ChartGraphNode` values as arcs around a circle and draws a ribbon across it for every `ChartGraphLink`. An arc is as long as the total of its links and a ribbon is as thick as its link's value. Links refer to nodes by `Id`. ```razor ``` ```csharp private readonly ChartGraphNode[] _teams = [new("design", "Design"), new("eng", "Engineering"), new("sales", "Sales")]; private readonly ChartGraphLink[] _projects = [new("design", "eng", 8), new("eng", "sales", 5), new("sales", "design", 3)]; ``` ## Flows in both directions Add a link each way to show a two-way flow. Each ribbon takes the color of the node it starts at, so the mix of colors arriving at an arc shows where its traffic comes from. ```razor ``` ```csharp private readonly ChartGraphNode[] _plans = [new("free", "Free"), new("team", "Team"), new("business", "Business"), new("enterprise", "Enterprise")]; private readonly ChartGraphLink[] _switches = [ new("free", "team", 420), new("team", "free", 90), new("team", "business", 260), new("business", "team", 70), new("business", "enterprise", 110), new("enterprise", "business", 25), new("free", "business", 60) ]; ``` ## Dominant links Because thickness follows value, one heavy relationship stands out from many light ones at a glance. ```razor ``` ```csharp private readonly ChartGraphNode[] _regions = [ new("eu", "Europe"), new("na", "North America"), new("as", "Asia"), new("sa", "South America"), new("af", "Africa") ]; private readonly ChartGraphLink[] _trade = [ new("eu", "na", 620), new("as", "na", 540), new("as", "eu", 480), new("na", "sa", 90), new("eu", "af", 70), new("as", "af", 55), new("sa", "eu", 40) ]; ``` ## When to use Use a chord diagram to compare weighted flows among a handful of nodes. Nodes are named in the legend, in the colors of their arcs. Links that name a missing node, or join a node to itself, are left out. ## Summary Tooltips and the table view give the source, target and value of each link. Tooltips also give the total of each node. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwChordDiagramChart A chord diagram: nodes arranged as arcs around a circle, each as long as the total of its links, with a ribbon across the circle for every link, as thick as the link's value. | Parameter | Type | Description | | --- | --- | --- | | `Nodes` | `IReadOnlyList` | Gets or sets the nodes. Each needs a unique `Id`; repeats are left out. | | `Links` | `IReadOnlyList` | Gets or sets the links between nodes, by node identifier. Links that name a missing node, or join a node to itself, are left out. | | `SourceHeader` | `string?` | Gets or sets the heading of the column naming where each link starts in the table view. Defaults to the localized `Chart_Source` text ("Source"). | | `TargetHeader` | `string?` | Gets or sets the heading of the column naming where each link ends in the table view. Defaults to the localized `Chart_Destination` text ("Target"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels a link's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwCircularTreemapChart > TwCircularTreemapChart is a Blazor circle packing chart: a circle per leaf of a tree, sized by value and packed inside its parent's circle. Documentation page: https://twblazor.com/chart/circular-treemap ## Basic usage `TwCircularTreemapChart` takes a tree of `ChartHierarchyNode` values. Every leaf becomes a circle whose area follows its `Value`, packed inside a circle for its parent. Each top-level node has its own color and legend entry. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _folders = [ new("Documents", Children: [new("Reports", 32), new("Notes", 18), new("Invoices", 9)]), new("Media", Children: [new("Images", 45), new("Audio", 20), new("Video", 64)]) ]; ``` ## Deeper trees Nodes nest to any depth, and every level gets its own enclosing circle, so the grouping reads at a glance. A larger `Height` gives small circles room for their names. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _organisation = [ new("Product", Children: [ new("Engineering", Children: [new("Platform", 24), new("Web", 18), new("Mobile", 14), new("Data", 9)]), new("Design", Children: [new("Research", 6), new("Interface", 11)]) ]), new("Commercial", Children: [ new("Sales", Children: [new("Enterprise", 16), new("Mid-market", 12), new("Partners", 5)]), new("Marketing", Children: [new("Brand", 7), new("Growth", 10)]) ]), new("Operations", Children: [new("Finance", 8), new("People", 6), new("Legal", 3)]) ]; ``` ## A flat list Without children every node is a leaf, and the chart becomes a packed bubble chart: one circle and one color per value. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _cities = [ new("Tokyo", 37.2), new("Delhi", 33.8), new("Shanghai", 29.9), new("Dhaka", 23.9), new("Cairo", 22.6), new("Lagos", 16.5), new("London", 9.7), new("Sydney", 5.2) ]; ``` ## When to use Circles leave gaps, so sizes are harder to compare than on [TwConvexTreemapChart](https://twblazor.com/chart/convex-treemap.md); in return the nesting is easier to see. A name too long for its circle is cut short. Nodes with no value are left out. ## Summary Tooltips and the table view give the path and the value of each leaf. Tooltips also give its share of the whole. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCircularTreemapChart A circular treemap (circle packing): a circle for every leaf of a tree, with an area that follows its value, packed inside a circle for its parent, so the grouping is visible as well as the sizes. | Parameter | Type | Description | | --- | --- | --- | | `Roots` | `IReadOnlyList` | Gets or sets the top-level nodes of the tree. | | `LabelHeader` | `string?` | Gets or sets the heading of the node column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwColumnChart > TwColumnChart is a Blazor column chart that compares categories with vertical columns. Supports grouped, stacked, 100% stacked and diverging layouts. Documentation page: https://twblazor.com/chart/column ## Basic usage `TwColumnChart` draws vertical columns whose length shows the value of each category. Columns suit short category labels and a handful of categories, and read naturally for values over time. Pass the category labels as `Categories` and one or more `ChartSeries` as `Series`. For the other direction use [TwBarChart](https://twblazor.com/chart/bar.md); the parameters are identical. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "East", "West"]; private readonly ChartSeries[] _revenue = [new("Revenue", [420, 310, 275, 380])]; private readonly ChartSeries[] _yearly = [ new("2024", [360, 290, 240, 330]), new("2025", [420, 310, 275, 380]) ]; ``` ## Value labels Set `ShowValues` to label each bar with its value. It works best with few bars; with many, the axis and tooltips carry the values more cleanly. ```razor ``` ## Grouped Pass more than one series and each category shows its series side by side. A legend appears automatically, and clicking an entry hides that series. ```razor ``` ## Stacked Set `Stacking` to `ChartStacking.Stacked` to pile the series on top of each other, so each bar shows the category total as well as its parts. ```razor ``` ## 100% stacked `ChartStacking.Percent` scales every bar to the same length, so the chart compares shares instead of totals. Tooltips and the table view still show the original values. ```razor ``` ## Diverging Negative values grow the other way from the baseline. Stack a positive and a negative series to make a diverging chart, for example agreement against disagreement. ```razor ``` ```csharp private readonly string[] _teams = ["Design", "Engineering", "Sales", "Support"]; private readonly ChartSeries[] _sentiment = [ new("Agree", [62, 48, 35, 54]), new("Disagree", [-18, -30, -41, -22]) ]; ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwColumnChart A column chart: vertical bars whose height shows the value of each category. With several series it becomes a grouped, stacked or 100% stacked column chart, see `Stacking`. | Parameter | Type | Description | | --- | --- | --- | | `Stacking` | `ChartStacking` | Gets or sets how multiple series share a category: side by side, stacked, or stacked to 100%. | | `ShowValues` | `bool` | Gets or sets whether each bar is labelled with its value. Ignored when `Stacking` is on. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwContourChart > TwContourChart is a Blazor contour plot that joins the places where a measured surface has the same value, like height lines on a map. Documentation page: https://twblazor.com/chart/contour ## Basic usage `TwContourChart` draws contour lines over a surface estimated from scattered samples. Give each `ChartPoint` its position as `X` and `Y` and its measurement as `Size`. A stronger line marks a higher value, and each sample is drawn as a dot. ```razor ``` ```csharp private readonly ChartPointSeries[] _temperatures = [ new("Sensors", [ new(0, 0, Size: 17.5), new(4, 0, Size: 18.2), new(8, 0, Size: 19.1), new(0, 3, Size: 18.4), new(4, 3, Size: 20.6), new(8, 3, Size: 22.3), new(0, 6, Size: 19.0), new(4, 6, Size: 21.8), new(8, 6, Size: 24.5) ]) ]; ``` ## Levels `Levels` sets how many lines are drawn, from 2 to 10, spaced evenly between the lowest and highest measurement. More lines show the slope in more detail: where they bunch together the surface is steep. ```razor
``` ## Two peaks Closed rings mark a peak or a hollow. This survey has two hills with a saddle between them. Name the samples with `Label` to title their tooltips. ```razor ``` ```csharp // A 7 by 5 grid of readings that fall away from two transmitters. private readonly ChartPointSeries[] _signal = [ new("Transmitters", [new(2, 3, "North mast", 60), new(8, 1.5, "South mast", 52)]), new("Survey", [.. Enumerable.Range(0, 35).Select(index => { var (x, y) = (index % 7 * 1.6, index / 7 * 1.0); var north = 60 / (1 + Math.Pow(x - 2, 2) + Math.Pow(y - 3, 2)); var south = 52 / (1 + Math.Pow(x - 8, 2) + Math.Pow(y - 1.5, 2)); return new ChartPoint(x, y, Size: Math.Round(north + south, 1)); })]) ]; ``` ## When to use Use a contour plot for a measurement that varies smoothly across two dimensions. The surface between samples is estimated, so the lines are a guide and the dots are the measurements. Points without a `Size` are left out, and at least three samples are needed. ## Summary Tooltips and the table view give the position and the value of each sample. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwContourChart A contour plot: lines joining the places where a measured surface has the same value, like the height lines on a map, drawn from samples taken at scattered positions. | Parameter | Type | Description | | --- | --- | --- | | `Levels` | `int` | Gets or sets how many contour lines are drawn, from 2 to 10. | | `ValueTitle` | `string?` | Gets or sets the label for a sample's measurement in tooltips and the table view. Defaults to the localized `Chart_Value` text ("Value"). | | `Series` | `IReadOnlyList` | Gets or sets the series of points to summarise. Every series is combined into one cloud. | | `XTitle` | `string` | Gets or sets the title of the horizontal axis. It also labels the X value in tooltips and the table view. | | `YTitle` | `string` | Gets or sets the title of the vertical axis. It also labels the Y value in tooltips and the table view. | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwConvexTreemapChart > TwConvexTreemapChart is a Blazor treemap for trees: cut-cornered tiles sized by value and grouped with the other leaves of their parent. Documentation page: https://twblazor.com/chart/convex-treemap ## Basic usage `TwConvexTreemapChart` takes a tree of `ChartHierarchyNode` values and fills the plot with a tile for every leaf, sized by its `Value`. The leaves of one parent sit together and share its color, with a gap around the group. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _budget = [ new("Product", Children: [new("Research", 36), new("Design", 24), new("Engineering", 58)]), new("Operations", Children: [new("Support", 22), new("Hosting", 18)]) ]; ``` ## Many leaves Tiles are laid out largest first and kept close to square, so a long tail of small values stays readable. Tiles with room show their name; every tile has a tooltip. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _bundle = [ new("Framework", Children: [new("Runtime", 412), new("Router", 96), new("Forms", 74), new("Http", 38)]), new("Interface", Children: [new("Components", 268), new("Icons", 142), new("Charts", 118), new("Theme", 44)]), new("Application", Children: [new("Pages", 186), new("Services", 92), new("Models", 31), new("Resources", 27), new("Utilities", 12)]) ]; ``` ## Three levels Groups nest inside groups. Each level is inset a little further, and the tooltip and table view give a leaf's full path so two leaves with the same name stay distinct. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _sales = [ new("Europe", Children: [ new("United Kingdom", Children: [new("Hardware", 4.2), new("Software", 6.8), new("Services", 2.4)]), new("Germany", Children: [new("Hardware", 3.1), new("Software", 4.4)]), new("France", Children: [new("Hardware", 1.9), new("Software", 2.7)]) ]), new("Americas", Children: [ new("United States", Children: [new("Hardware", 7.5), new("Software", 11.3), new("Services", 5.1)]), new("Canada", Children: [new("Hardware", 1.4), new("Software", 2.2)]) ]), new("Asia Pacific", Children: [new("Japan", 5.6), new("Australia", 3.3), new("Singapore", 1.8)]) ]; ``` ## When to use Use a convex treemap to compare the leaves of a tree by size. Nodes with no value are left out. For a single flat list of values, [TwTreemapChart](https://twblazor.com/chart/treemap.md) does the same job without the grouping. ## Summary Tooltips and the table view give the path and the value of each leaf. Tooltips also give its share of the whole. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwConvexTreemapChart A convex treemap: the leaves of a tree drawn as tiles with cut corners that fill the plot, each with an area that follows its value and grouped with the other leaves of its parent. | Parameter | Type | Description | | --- | --- | --- | | `Roots` | `IReadOnlyList` | Gets or sets the top-level nodes of the tree. | | `LabelHeader` | `string?` | Gets or sets the heading of the node column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwDendrogramChart > TwDendrogramChart is a Blazor dendrogram: a tree drawn from its root down to its leaves with a bracket joining every branch to its parent. Documentation page: https://twblazor.com/chart/dendrogram ## Basic usage `TwDendrogramChart` draws a tree of `ChartHierarchyNode` values from the root at the top to the leaves along the bottom. Leaves are named on the axis under the plot, and branches are named beside the point where they split. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _documents = [ new("All documents", Children: [ new("Research", Children: [new("Paper A", 1), new("Paper B", 1)]), new("Guides", Children: [new("Guide A", 1), new("Guide B", 1)]) ]) ]; ``` ## Uneven depth Leaves line up along the bottom whatever their depth, so a branch that splits again and again is easy to compare with one that ends early. This is the usual way to draw a classification. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _vertebrates = [ new("Vertebrates", Children: [ new("Fish", Children: [new("Sharks", 1), new("Salmon", 1)]), new("Tetrapods", Children: [ new("Amphibians", Children: [new("Frogs", 1), new("Newts", 1)]), new("Amniotes", Children: [ new("Mammals", Children: [new("Whales", 1), new("Bats", 1), new("Primates", 1)]), new("Reptiles", Children: [new("Lizards", 1), new("Birds", 1)]) ]) ]) ]) ]; ``` ## Values Give leaves a `Value` and every branch shows the total of the leaves beneath it in its tooltip and in the table view. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _buildSteps = [ new("Build", Children: [ new("Compile", Children: [new("Library", 42), new("Docs", 31), new("Tests", 18)]), new("Verify", Children: [new("Unit", 64), new("Browser", 97)]), new("Package", 12) ]) ]; ``` ## Several roots Pass more than one root to draw separate trees side by side. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _teams = [ new("Asha", Children: [new("Ben", 1), new("Chloe", 1)]), new("Dmitri", Children: [new("Elena", 1), new("Farid", 1), new("Grace", 1)]) ]; ``` ## When to use Use a dendrogram to show how items group into clusters, when the structure matters more than the sizes. To compare sizes use [TwSunburstChart](https://twblazor.com/chart/sunburst.md) or [TwConvexTreemapChart](https://twblazor.com/chart/convex-treemap.md). ## Summary Tooltips and the table view give the path and the value of each node. The arrow keys visit the nodes from the root down, a branch before its children. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDendrogramChart A dendrogram: a tree drawn from its root at the top down to its leaves along the bottom, with every branch joined to its parent by a bracket, for showing how items group into clusters. | Parameter | Type | Description | | --- | --- | --- | | `Roots` | `IReadOnlyList` | Gets or sets the top-level nodes of the tree. | | `LabelHeader` | `string?` | Gets or sets the heading of the node column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwDensityPlotChart > TwDensityPlotChart is a Blazor density plot that draws a smooth curve per group showing where its raw values concentrate. Documentation page: https://twblazor.com/chart/density-plot ## Basic usage `TwDensityPlotChart` takes groups of raw observations as `ChartSample` values and draws a smooth curve for each, tall where its values cluster. You pass the observations; the chart estimates the curve. ```razor ``` ```csharp private readonly ChartSample[] _checkout = [ new("Checkout", [31, 34, 36, 38, 39, 41, 42, 42, 44, 45, 47, 48, 51, 55, 62, 74]) ]; ``` ## Comparing groups Several groups share one axis and one vertical scale, so a taller curve always means a tighter cluster. Each group gets a legend entry; click one to hide its curve and let the axis refit the rest. ```razor ``` ```csharp private readonly ChartSample[] _releases = [ new("v1.8", [820, 860, 905, 930, 960, 990, 1010, 1040, 1080, 1150, 1230, 1400]), new("v1.9", [640, 690, 720, 745, 760, 790, 805, 830, 870, 910, 980]), new("v2.0", [410, 430, 445, 450, 462, 470, 478, 490, 505, 530, 560]) ]; ``` ## Two peaks A density plot shows shapes that a box plot hides. Here the same service has a fast cached path and a slow uncached one, which appear as two separate humps. ```razor ``` ```csharp private readonly ChartSample[] _latency = [ new("Latency", [18, 20, 21, 22, 22, 23, 24, 25, 26, 28, 31, 140, 152, 158, 161, 165, 170, 174, 181, 190]) ]; ``` ## When to use Use a density plot to compare the shape of a few distributions. Curves run a little past the lowest and highest observation so they can fall back to zero, and there is no vertical axis because density has no unit a reader needs. For many groups use [TwRidgelinePlotChart](https://twblazor.com/chart/ridgeline.md). ## Summary Tooltips and the table view give the count, minimum, median and maximum of each group. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDensityPlotChart A density plot: a smooth curve for each group of raw observations showing where its values concentrate, for comparing the shape of distributions on one axis. | Parameter | Type | Description | | --- | --- | --- | | `Samples` | `IReadOnlyList` | Gets or sets the groups of raw observations to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the group column in the table view. Defaults to the localized `Chart_Group` text ("Group"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwDotPlotChart > TwDotPlotChart is a Blazor dot plot that compares series by position on a shared line per category. The scale does not need to start at zero. Documentation page: https://twblazor.com/chart/dot-plot ## Basic usage `TwDotPlotChart` places one dot per series on a shared line for each category, so values are compared by position rather than length. Because nothing is measured from a baseline, the scale can zoom in on the range the data occupies, which makes small differences visible. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "East", "West"]; private readonly ChartSeries[] _yearly = [ new("2024", [360, 290, 240, 330]), new("2025", [420, 310, 275, 380]) ]; ``` ## Vertical Set `Vertical` to place the categories along the bottom with values running upwards. ```razor ``` ## Related charts To draw attention to the gap between the dots, use [TwDumbbellChart](https://twblazor.com/chart/dumbbell.md), which joins them with a bar. To show every raw observation in a group, use [TwStripPlotChart](https://twblazor.com/chart/strip-plot.md). ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDotPlotChart A dot plot: one dot per series on a shared line for each category, so values are compared by position. Unlike bars the scale does not have to start at zero, which suits values that sit in a narrow range. | Parameter | Type | Description | | --- | --- | --- | | `Vertical` | `bool` | Gets or sets whether categories run left to right with values bottom to top, instead of the default rows with values left to right. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwDumbbellChart > TwDumbbellChart is a Blazor dumbbell chart: two dots per category joined by a bar, highlighting the gap between values such as before and after. Documentation page: https://twblazor.com/chart/dumbbell ## Basic usage `TwDumbbellChart` is a dot plot whose dots are joined by a bar. The bar makes the size of the gap the first thing the reader sees, which suits before and after, target and actual, or any two groups. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "East", "West"]; private readonly ChartSeries[] _yearly = [ new("2024", [360, 290, 240, 330]), new("2025", [420, 310, 275, 380]) ]; ``` ## Vertical Set `Vertical` to place the categories along the bottom. ```razor ``` ## More than two series The bar always spans from the lowest to the highest value in the category, so a third series sits somewhere along it. ```razor ``` ```csharp private readonly string[] _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; private readonly ChartSeries[] _visitors = [ new("Organic", [42, 48, 55, 61, 58, 70]), new("Paid", [30, 34, 31, 45, 52, 49]), new("Referral", [12, 15, 21, 19, 26, 33]) ]; ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDumbbellChart A dumbbell chart: a dot plot whose dots are joined by a bar, drawing the eye to the gap between two (or more) values for each category, such as before and after. | Parameter | Type | Description | | --- | --- | --- | | `Vertical` | `bool` | Gets or sets whether categories run left to right with values bottom to top, instead of the default rows with values left to right. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwEulerDiagramChart > TwEulerDiagramChart is a Blazor Euler diagram: sets as circles sized by their members, overlapping only where they share some. Documentation page: https://twblazor.com/chart/euler-diagram ## Basic usage `TwEulerDiagramChart` draws each `ChartSet` as a circle whose area follows its size. Two circles overlap only when a `ChartSetIntersection` says they share elements, and by an area that follows how many. ```razor ``` ```csharp private readonly ChartSet[] _groups = [new("Design", 42), new("Research", 35)]; private readonly ChartSetIntersection[] _sharedMembers = [new("Design", "Research", 18)]; ``` ## Separate sets Sets with no intersection are drawn apart. Here two products share customers and a third has none in common with either. ```razor ``` ```csharp private readonly ChartSet[] _products = [new("Accounts", 64), new("Payroll", 38), new("Rostering", 12)]; private readonly ChartSetIntersection[] _sharedCustomers = [new("Accounts", "Payroll", 22)]; ``` ## A set inside another When a set shares all of its elements with a larger one, it is drawn inside it. Every premium subscriber here is also a registered user. ```razor ``` ```csharp private readonly ChartSet[] _accounts = [new("Registered", 90), new("Premium", 18)]; private readonly ChartSetIntersection[] _accountOverlap = [new("Registered", "Premium", 18)]; ``` ## Three overlapping sets With three sets the circles are placed so each pair overlaps as closely as circles allow to the number given. Read exact figures from the labels, tooltips and table view. ```razor ``` ```csharp private readonly ChartSet[] _languages = [new("English", 120), new("Spanish", 55), new("French", 30)]; private readonly ChartSetIntersection[] _bilingual = [ new("English", "Spanish", 32), new("English", "French", 18), new("Spanish", "French", 6) ]; ``` ## When to use Use an Euler diagram when the sizes of the sets matter. Up to three sets are drawn, and sets with no size are left out. To show every possible overlap with equal circles, use [TwVennDiagramChart](https://twblazor.com/chart/venn-diagram.md). ## Summary Tooltips and the table view give the size of each set and of each overlap. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwEulerDiagramChart An Euler diagram: up to three sets drawn as circles whose areas follow their sizes, overlapping only where they share elements and by an area that follows how many. | Parameter | Type | Description | | --- | --- | --- | | `Sets` | `IReadOnlyList` | Gets or sets the sets to draw. Up to three are shown; sets with no size are left out. | | `Intersections` | `IReadOnlyList` | Gets or sets how many elements each pair of sets shares. Each is named by the labels of its two sets. | | `LabelHeader` | `string?` | Gets or sets the heading of the set column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the size column in the table view. It also labels a set's size in tooltips. Defaults to the localized `Chart_Size` text ("Size"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwFlowchart > TwFlowchart is a Blazor flowchart: the steps of a process as boxes in columns, with an arrow for every link from one step to the next. Documentation page: https://twblazor.com/chart/flowchart ## Basic usage `TwFlowchart` draws each `ChartGraphNode` as a box and each `ChartGraphLink` as an arrow. Steps are set out in columns from left to right, each to the right of every step that leads to it. Links refer to nodes by `Id`. ```razor ``` ```csharp private readonly ChartGraphNode[] _reviewSteps = [new("submit", "Submit"), new("review", "Review"), new("publish", "Publish")]; private readonly ChartGraphLink[] _reviewLinks = [new("submit", "review"), new("review", "publish")]; ``` ## Branches Steps reached from the same step share a column and are stacked in the order given, so a decision fans out and its branches join again further on. ```razor ``` ```csharp private readonly ChartGraphNode[] _ticketSteps = [ new("open", "Opened"), new("triage", "Triage"), new("answer", "Answer"), new("fix", "Fix"), new("refund", "Refund"), new("close", "Closed") ]; private readonly ChartGraphLink[] _ticketLinks = [ new("open", "triage"), new("triage", "answer"), new("triage", "fix"), new("triage", "refund"), new("answer", "close"), new("fix", "close"), new("refund", "close") ]; ``` ## Parallel work A pipeline that runs several jobs at once shows as a column of boxes fed by one step and feeding the next. ```razor ``` ```csharp private readonly ChartGraphNode[] _pipelineSteps = [ new("commit", "Commit"), new("build", "Build"), new("unit", "Unit tests"), new("browser", "Browser tests"), new("a11y", "Accessibility"), new("lint", "Lint"), new("package", "Package"), new("deploy", "Deploy") ]; private readonly ChartGraphLink[] _pipelineLinks = [ new("commit", "build"), new("build", "unit"), new("build", "browser"), new("build", "a11y"), new("build", "lint"), new("unit", "package"), new("browser", "package"), new("a11y", "package"), new("lint", "package"), new("package", "deploy") ]; ``` ## Setting the column Set a node's `Stage` to move it further right than its links alone would place it. Here the manual check is held back to line up with the final column of automatic checks. ```razor ``` ```csharp private readonly ChartGraphNode[] _orderSteps = [ new("order", "Order"), new("stock", "Stock"), new("fraud", "Fraud"), new("manual", "Manual check", Stage: 2), new("ship", "Ship") ]; private readonly ChartGraphLink[] _orderLinks = [ new("order", "stock"), new("stock", "fraud"), new("order", "manual"), new("fraud", "ship"), new("manual", "ship") ]; ``` ## When to use Use a flowchart for the steps of a process. A name too long for its box is cut short; the tooltip has it in full. Link values are not shown: to show how much flows along each link, use [TwSankeyChart](https://twblazor.com/chart/sankey.md). ## Summary Tooltips and the table view give the source and target of each link. The arrow keys move through the steps in the order given. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwFlowchart A flowchart: the steps of a process drawn as boxes in columns from left to right, with an arrow for every link from one step to the next. | Parameter | Type | Description | | --- | --- | --- | | `Nodes` | `IReadOnlyList` | Gets or sets the nodes. Each needs a unique `Id`; repeats are left out. | | `Links` | `IReadOnlyList` | Gets or sets the links between nodes, by node identifier. Links that name a missing node, or join a node to itself, are left out. | | `SourceHeader` | `string?` | Gets or sets the heading of the column naming where each link starts in the table view. Defaults to the localized `Chart_Source` text ("Source"). | | `TargetHeader` | `string?` | Gets or sets the heading of the column naming where each link ends in the table view. Defaults to the localized `Chart_Destination` text ("Target"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels a link's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwFunnelChart > TwFunnelChart is a Blazor funnel chart showing how much remains at each stage of a process. Invert it to draw a pyramid chart. Documentation page: https://twblazor.com/chart/funnel ## Basic usage `TwFunnelChart` stacks the stages of a process, each as wide as its value, so the drop between stages is visible. Tooltips give each stage as a share of the first. The stages are an ordered sequence, so they share one hue that fades from first to last. ```razor ``` ```csharp private readonly ChartValue[] _funnel = [ new("Visited", 12000), new("Added to basket", 5400), new("Started checkout", 3100), new("Paid", 2200) ]; ``` ## Pyramid Set `Inverted` to draw the stages from the bottom up, which turns the funnel into a pyramid. ```razor ``` ```csharp private readonly ChartValue[] _tiers = [ new("Self service", 900), new("Front line", 520), new("Specialists", 210), new("Engineering", 60) ]; ``` ## Labels `ShareLabel` renames the share of the first stage in tooltips. ```razor ``` ## Summary Tooltips and the table view give the value of each stage. Tooltips also give its share of the first stage. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwFunnelChart A funnel chart: stacked stages whose width shows how much remains at each step of a process, such as a sales pipeline. Set `Inverted` to draw it as a pyramid. | Parameter | Type | Description | | --- | --- | --- | | `Inverted` | `bool` | Gets or sets whether the stages are drawn bottom to top, turning the funnel into a pyramid. | | `ShareLabel` | `string?` | Gets or sets the label for a stage's share of the first stage in tooltips. Defaults to the localized `Chart_OfFirstStage` text ("Of first stage"). | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwGanttChart > TwGanttChart is a Blazor Gantt chart: a horizontal bar per task from its start date to its end date, showing a schedule and overlaps. Documentation page: https://twblazor.com/chart/gantt ## Basic usage `TwGanttChart` draws a bar per `ChartTask` from its start date to its end date, in the order given, so the schedule and any overlaps are visible. ```razor ``` ```csharp private readonly ChartTask[] _tasks = [ new("Research", new DateTime(2026, 1, 5, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 1, 23, 0, 0, 0, DateTimeKind.Local)), new("Design", new DateTime(2026, 1, 19, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 2, 13, 0, 0, 0, DateTimeKind.Local)), new("Build", new DateTime(2026, 2, 9, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 20, 0, 0, 0, DateTimeKind.Local)), new("Test", new DateTime(2026, 3, 9, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 31, 0, 0, 0, DateTimeKind.Local)) ]; ``` ## Date format `DateFormat` takes any .NET date format string and applies to the axis, tooltips and table view. ```razor ``` ## Labels `StartLabel`, `EndLabel` and `LabelHeader` rename the values in tooltips and the table view. ```razor ``` ## Summary Tooltips and the table view give the start and end of each task. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwGanttChart A Gantt chart: a horizontal bar per task from its start date to its end date, showing a schedule and where tasks overlap. | Parameter | Type | Description | | --- | --- | --- | | `Tasks` | `IReadOnlyList` | Gets or sets the tasks to plot, in the order they should be listed. | | `DateFormat` | `string` | Gets or sets the .NET date format string used on the axis, tooltips and table view. | | `LabelHeader` | `string?` | Gets or sets the heading of the task column in the table view. Defaults to the localized `Chart_Task` text ("Task"). | | `StartLabel` | `string?` | Gets or sets the label for a task's start date. Defaults to the localized `Chart_Start` text ("Start"). | | `EndLabel` | `string?` | Gets or sets the label for a task's end date. Defaults to the localized `Chart_End` text ("End"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwGaugeChart > TwGaugeChart is a Blazor circular gauge: an arc filled in proportion to one value between a minimum and a maximum. Documentation page: https://twblazor.com/chart/gauge ## Basic usage `TwGaugeChart` fills an arc in proportion to a single `Value` and prints it in the middle. `Label` says what it measures. ```razor ``` ## Range The arc runs from `Min` (0 by default) to `Max` (100 by default). A value outside the range fills or empties the arc but is still printed as given. ```razor ``` ## Size and format `Height` sets how large the gauge may grow and `ValueFormat` formats the figure. ```razor
``` ## Summary Tooltips and the table view give the value of the gauge and the range it is measured against. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwGaugeChart A circular gauge: an arc filled in proportion to a single value between a minimum and a maximum, with the value shown in the middle. | Parameter | Type | Description | | --- | --- | --- | | `Value` | `double` | Gets or sets the value the gauge shows. | | `Min` | `double` | Gets or sets the value at the start of the arc. | | `Max` | `double` | Gets or sets the value at the end of the arc. | | `Label` | `string?` | Gets or sets what the value measures, shown under it. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwHeatmapChart > TwHeatmapChart is a Blazor heatmap: a grid of cells whose color intensity shows the value where a row and a column meet. Documentation page: https://twblazor.com/chart/heatmap ## Basic usage `TwHeatmapChart` lays each series out as a row and each category as a column, and shades the cell where they meet by its value. Intensity uses a single hue, so darker always means more. ```razor ``` ```csharp private readonly string[] _days = ["Mon", "Tue", "Wed", "Thu", "Fri"]; private readonly ChartSeries[] _shifts = [ new("Morning", [34, 28, 31, 25, 40]), new("Afternoon", [52, 47, 58, 49, 61]), new("Evening", [18, 22, 15, 27, 33]) ]; ``` ## Value labels Set `ShowValues` to print each value on its cell. The text switches between dark and light ink to stay readable on any shade. ```razor ``` ## Labels `ValueLabel` names the value in tooltips and `CategoryHeader` names the first column of the table view. ```razor ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwHeatmapChart A heatmap: a grid of cells whose color intensity shows the value where a series (row) meets a category (column). | Parameter | Type | Description | | --- | --- | --- | | `ShowValues` | `bool` | Gets or sets whether each cell is labelled with its value. | | `ValueLabel` | `string?` | Gets or sets the label for a cell's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwHexbinChart > TwHexbinChart is a Blazor hexbin chart that tiles the plot with hexagons shaded by how many points fall in each, for scatter data too dense to read. Documentation page: https://twblazor.com/chart/hexbin ## Basic usage `TwHexbinChart` takes the same `ChartPointSeries` as a scatter plot, tiles the plot with hexagons and shades each by how many points fall inside it. Use it when there are so many points that dots would pile into a blob. ```razor ``` ```csharp // A repeatable cloud of 400 sessions: longer sessions view more pages, with some scatter. private readonly ChartPointSeries[] _sessions = [ new("Sessions", [.. Enumerable.Range(0, 400).Select(index => { var minutes = 2 + index % 37 * 0.6 + Math.Sin(index * 1.7) * 3; var pages = 1 + minutes * 0.45 + Math.Cos(index * 2.3) * 2.5; return new ChartPoint(Math.Max(0.5, minutes), Math.Max(1, pages)); })]) ]; ``` ## Bin size `BinWidth` is the width of a hexagon as a percentage of the plot's width, from 4 to 25. Smaller hexagons show finer detail but need more points to fill; larger ones smooth out the noise. ```razor
``` ## Several series Every series is combined into one cloud before counting, so you can pass data in whatever groups you hold it in. Here two clusters of readings show as two dark patches. ```razor ``` ```csharp private readonly ChartPointSeries[] _readings = [ new("Greenhouse", [.. Enumerable.Range(0, 180).Select(index => new ChartPoint(27 + Math.Sin(index * 0.9) * 3, 72 + Math.Cos(index * 1.3) * 8))]), new("Warehouse", [.. Enumerable.Range(0, 180).Select(index => new ChartPoint(16 + Math.Sin(index * 1.1) * 4, 41 + Math.Cos(index * 0.7) * 6))]) ]; ``` ## When to use Use a hexbin chart when a scatter plot has too many points to tell apart. Shading uses a single hue, so darker always means more points, and hexagons with no points are left out. For fewer points use [TwScatterChart](https://twblazor.com/chart/scatter.md). ## Summary Tooltips and the table view give the average position and the count of the points in each hexagon. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwHexbinChart A hexbin chart: the plot is tiled with hexagons and each is shaded by how many points fall inside it, for showing where a scatter plot too dense to read is most crowded. | Parameter | Type | Description | | --- | --- | --- | | `BinWidth` | `double` | Gets or sets the width of a hexagon as a percentage of the plot's width, from 4 to 25. | | `CountLabel` | `string?` | Gets or sets the label for a hexagon's count in tooltips and the table view. Defaults to the localized `Chart_Count` text ("Count"). | | `Series` | `IReadOnlyList` | Gets or sets the series of points to summarise. Every series is combined into one cloud. | | `XTitle` | `string` | Gets or sets the title of the horizontal axis. It also labels the X value in tooltips and the table view. | | `YTitle` | `string` | Gets or sets the title of the vertical axis. It also labels the Y value in tooltips and the table view. | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwHistogramChart > TwHistogramChart is a Blazor histogram that groups raw values into equal-width bins to reveal the shape of a distribution. Documentation page: https://twblazor.com/chart/histogram ## Basic usage `TwHistogramChart` takes raw `Values`, groups them into equal-width bins and draws a column per bin showing how many values fall in it. You pass the observations; the chart does the counting. ```razor ``` ```csharp private readonly double[] _responseTimes = [ 112, 120, 131, 135, 138, 142, 144, 149, 151, 153, 156, 158, 160, 163, 167, 170, 172, 176, 181, 185, 190, 196, 204, 215, 228, 240, 262, 290 ]; ``` ## Bin count The number of bins follows Sturges' rule unless you set `BinCount`. Fewer bins show the overall shape; more show detail. ```razor ``` ## Labels `RangeLabel` and `CountLabel` name the two columns of the table view, and `CountLabel` also titles the axis. ```razor ``` ## Summary Tooltips and the table view give the range and count of each bin. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwHistogramChart A histogram: raw values grouped into equal-width bins, with a column per bin showing how many values fall in it, revealing the shape of a distribution. | Parameter | Type | Description | | --- | --- | --- | | `Values` | `IReadOnlyList` | Gets or sets the raw values to group. | | `BinCount` | `int?` | Gets or sets how many bins to group the values into. | | `RangeLabel` | `string?` | Gets or sets the label for a bin's range in tooltips and the table view. Defaults to the localized `Chart_Range` text ("Range"). | | `CountLabel` | `string?` | Gets or sets the label for a bin's count in tooltips and the table view. Defaults to the localized `Chart_Count` text ("Count"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwHorizonChart > TwHorizonChart is a Blazor horizon chart that folds each series into a compact row of layered bands, fitting many series into little height. Documentation page: https://twblazor.com/chart/horizon ## Basic usage `TwHorizonChart` gives each series its own short row. Values are cut into bands and the bands are layered, so a strong value shows as a darker color instead of a taller mark. Series are named on the axis. ```razor ``` ```csharp private readonly string[] _hours = ["00", "02", "04", "06", "08", "10", "12", "14", "16", "18", "20", "22"]; private readonly ChartSeries[] _services = [ new("API", [12, 8, 6, 14, 38, 52, 47, 55, 49, 36, 24, 15]), new("Web", [9, 5, 4, 11, 26, 31, 35, 33, 30, 28, 21, 12]), new("Search", [3, 2, 1, 4, 12, 19, 22, 18, 15, 11, 8, 4]), new("Reports", [1, 1, 22, 18, 3, 2, 2, 3, 2, 1, 1, 1]) ]; ``` ## Bands `BandCount` sets how many bands the values are cut into, from 1 to 6. More bands show finer differences in the same height but are harder to tell apart; three is a good default. ```razor ``` ## Above and below zero Negative values are drawn in the color for an unfavourable change, growing from the same baseline, so a row shows at a glance when a series was up and when it was down. ```razor ``` ```csharp private readonly string[] _weeks = ["W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8"]; private readonly ChartSeries[] _regions = [ new("North", [2.1, 3.4, 1.2, -0.8, -2.6, -1.1, 1.9, 4.2]), new("South", [-1.4, -2.2, -3.1, -1.9, 0.6, 2.4, 3.3, 2.8]), new("West", [0.4, 0.9, 1.6, 2.2, 2.9, 1.4, -0.3, -1.7]) ]; ``` ## When to use Use a horizon chart to fit many series into little height. Every row shares one scale, so the same darkness means the same magnitude in each. For a few series, [TwLineChart](https://twblazor.com/chart/line.md) is easier to read. ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwHorizonChart A horizon chart: one compact row per series in which the values are cut into bands and layered, so a strong value shows as a darker color instead of a taller mark. It fits many series into little height. | Parameter | Type | Description | | --- | --- | --- | | `BandCount` | `int` | Gets or sets how many bands the values are cut into, from 1 to 6. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwIconChart > TwIconChart is a Blazor icon chart and pictogram: values shown as rows of repeated icons, or as one icon sized by each value. Documentation page: https://twblazor.com/chart/icon ## Basic usage `TwIconChart` draws values with any `Icon` from the library. By default each value becomes a row of repeated icons, a pictogram, and the legend states what one icon stands for. ```razor ``` ```csharp private readonly ChartValue[] _offices = [ new("London", 48), new("Leeds", 22), new("Bristol", 31) ]; ``` ## Unit value A round amount is chosen so the largest value uses about ten icons. Set `UnitValue` to decide what one icon is worth. ```razor ``` ## Sized icons Set `Mode` to `IconChartMode.Size` to draw one icon per value, with its area following the value. ```razor ``` ## Accessibility The icons are decorative and hidden from assistive technology. The values are stated by the data points, tooltips and table view. ## Summary Tooltips and the table view give the value of each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwIconChart An icon chart: values shown with icons, either as a row of repeated icons per value (a pictogram) or as one icon per value sized by it. Icons make a chart quick to relate to, at the cost of precision. | Parameter | Type | Description | | --- | --- | --- | | `Icon` | `Icon` | Gets or sets the icon to draw. | | `Mode` | `IconChartMode` | Gets or sets whether values are shown by repeating the icon or by scaling it. | | `UnitValue` | `double?` | Gets or sets how much one icon stands for in `Count` mode. | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwLineChart > TwLineChart is a Blazor line chart for trends. Supports straight, smooth (spline) and step lines, markers and gaps for missing values. Documentation page: https://twblazor.com/chart/line ## Basic usage `TwLineChart` joins values in category order to show a trend. Hover or focus anywhere in a category and one tooltip lists every series at that point, so the pointer never has to land on a line. ```razor ``` ```csharp private readonly string[] _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; private readonly ChartSeries[] _visitors = [ new("Organic", [42, 48, 55, 61, 58, 70]), new("Paid", [30, 34, 31, 45, 52, 49]), new("Referral", [12, 15, 21, 19, 26, 33]) ]; ``` ## Spline Set `Curve` to `ChartCurve.Smooth` for a smooth curve through the points. The curve never overshoots the data, so it cannot suggest a peak that is not there. ```razor ``` ## Step line `ChartCurve.Step` holds each value until the next one, which suits values that change at discrete moments such as a price or a stock level. ```razor ``` ```csharp private readonly ChartSeries[] _price = [new("Price", [20, 20, 25, 25, 25, 30])]; ``` ## Markers A dot is drawn at each point when there are twelve categories or fewer. Set `ShowMarkers` to force them on or off. ```razor ``` ## Missing values A `null` value breaks the line instead of dropping to zero, so a gap in the data looks like a gap. ```razor ``` ```csharp private readonly ChartSeries[] _readings = [new("Temperature", [18, 21, null, null, 24, 22])]; ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwLineChart A line chart: values joined in category order to show a trend. Set `Curve` for a spline or step line chart. | Parameter | Type | Description | | --- | --- | --- | | `Curve` | `ChartCurve` | Gets or sets how points are joined: straight (line), smooth (spline) or stepped (step line). | | `ShowMarkers` | `bool?` | Gets or sets whether a dot is drawn at every point. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwLollipopChart > TwLollipopChart is a Blazor lollipop chart: a thin stem and a dot per value. A lighter alternative to bars when there are many categories. Documentation page: https://twblazor.com/chart/lollipop ## Basic usage `TwLollipopChart` draws a thin stem ending in a dot for each value. It reads like a column chart with far less ink, which keeps a chart with many similar values from turning into a wall of color. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "East", "West"]; private readonly ChartSeries[] _revenue = [new("Revenue", [420, 310, 275, 380])]; private readonly ChartSeries[] _yearly = [ new("2024", [360, 290, 240, 330]), new("2025", [420, 310, 275, 380]) ]; ``` ## Horizontal Set `Horizontal` to run the stems left to right with the categories listed down the side, which gives long labels room. ```razor ``` ## Several series With more than one series, each category shows a lollipop per series side by side. ```razor ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwLollipopChart A lollipop chart: a thin stem ending in a dot for each value. It reads like a bar chart with less ink, which helps when there are many categories with similar values. | Parameter | Type | Description | | --- | --- | --- | | `Horizontal` | `bool` | Gets or sets whether the stems run left to right with categories listed top to bottom. | | `ShowValues` | `bool` | Gets or sets whether each dot is labelled with its value. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwMarimekkoChart > TwMarimekkoChart is a Blazor Marimekko chart: columns whose widths show each category's total and whose segments show each series' share of it. Documentation page: https://twblazor.com/chart/marimekko ## Basic usage `TwMarimekkoChart` takes the same `Categories` and `Series` as a column chart. Each column is as wide as its category's total and is split into segments by each series' share, so the area of a segment is its value. ```razor ``` ```csharp private readonly string[] _regions = ["North", "South", "West"]; private readonly ChartSeries[] _products = [ new("Core", [50, 30, 20]), new("Plus", [25, 40, 35]), new("Pro", [15, 50, 10]) ]; ``` ## A market map The classic use is a market map: segments of a market across the bottom, sized by how big they are, and competitors up the side. A large block is a big prize; a tall segment in a narrow column is a strong position in a small market. ```razor ``` ```csharp private readonly string[] _industries = ["Finance", "Retail", "Healthcare", "Media", "Public sector"]; private readonly ChartSeries[] _providers = [ new("Northwind", [420, 180, 150, 60, 90]), new("Contoso", [260, 240, 90, 110, 40]), new("Fabrikam", [140, 120, 160, 30, 70]), new("Others", [80, 60, 50, 40, 20]) ]; ``` ## Uneven categories A column too narrow for its name loses the label under it but keeps its tooltip and its row in the table view. Segments with room show their share. ```razor ``` ```csharp private readonly string[] _channels = ["Email", "Chat", "Phone", "Post"]; private readonly ChartSeries[] _outcomes = [ new("Solved first time", [640, 410, 95, 4]), new("Solved later", [280, 120, 60, 9]), new("Escalated", [80, 30, 45, 7]) ]; ``` ## When to use Use a Marimekko chart when both the size of each category and its make-up matter. Missing and negative values count as zero. When the categories are similar in size, a 100% stacked [TwColumnChart](https://twblazor.com/chart/column.md) is easier to read. ## Summary Tooltips and the table view give the value of every series for each category. Tooltips also give the total of each category and its share of the whole. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwMarimekkoChart A Marimekko chart: a column for each category whose width shows the category's total, split into segments showing each series' share of it, so both the size of every category and its make-up are visible at once. | Parameter | Type | Description | | --- | --- | --- | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwMatrixChart > TwMatrixChart is a Blazor matrix chart: a grid with a dot sized by value where a row and a column meet, for two categorical dimensions. Documentation page: https://twblazor.com/chart/matrix ## Basic usage `TwMatrixChart` lays each series out as a row and each category as a column, and draws a dot where they meet, sized by the value. The area of the dot, not its width, follows the value. ```razor ``` ```csharp private readonly string[] _days = ["Mon", "Tue", "Wed", "Thu", "Fri"]; private readonly ChartSeries[] _shifts = [ new("Morning", [34, 28, 31, 25, 40]), new("Afternoon", [52, 47, 58, 49, 61]), new("Evening", [18, 22, 15, 27, 33]) ]; ``` ## Labels `ValueLabel` names the value in tooltips and `CategoryHeader` names the first column of the table view. ```razor ``` ## When to use Dot sizes are harder to compare than shades when values are close together. For a dense grid, or to print the values, use [TwHeatmapChart](https://twblazor.com/chart/heatmap.md). ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwMatrixChart A matrix chart: a grid with a dot where a series (row) meets a category (column), sized by the value, for spotting patterns across two categorical dimensions. | Parameter | Type | Description | | --- | --- | --- | | `ValueLabel` | `string?` | Gets or sets the label for a cell's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwNetworkDiagramChart > TwNetworkDiagramChart is a Blazor network diagram that arranges linked nodes close together and unrelated ones apart. Documentation page: https://twblazor.com/chart/network-diagram ## Basic usage `TwNetworkDiagramChart` draws each `ChartGraphNode` as a named dot and each `ChartGraphLink` as a line. You give no positions: linked nodes pull together and all nodes push apart until the layout settles. Links refer to nodes by `Id`. ```razor ``` ```csharp private readonly ChartGraphNode[] _services = [new("ui", "UI"), new("api", "API"), new("auth", "Auth"), new("db", "Database"), new("cache", "Cache")]; private readonly ChartGraphLink[] _dependencies = [ new("ui", "api"), new("ui", "auth"), new("api", "auth"), new("api", "db"), new("api", "cache") ]; ``` ## Hubs and clusters The layout brings structure out of a plain list of links. Here two tightly linked groups separate, joined through the one node that belongs to both. ```razor ``` ```csharp private readonly ChartGraphNode[] _people = [ new("ana", "Ana"), new("bo", "Bo"), new("cy", "Cy"), new("di", "Di"), new("eli", "Eli"), new("fay", "Fay"), new("gus", "Gus"), new("hal", "Hal"), new("ivy", "Ivy") ]; private readonly ChartGraphLink[] _collaborations = [ new("ana", "bo", 3), new("ana", "cy", 2), new("bo", "cy", 4), new("bo", "di", 1), new("cy", "di", 2), new("eli", "di", 2), new("eli", "fay", 3), new("eli", "gus", 1), new("fay", "gus", 2), new("gus", "hal", 4), new("fay", "hal", 1), new("hal", "ivy", 2) ]; ``` ## A star A single hub with many spokes settles into a star, and nodes with no links drift to the edge. ```razor ``` ```csharp private readonly ChartGraphNode[] _devices = [ new("switch", "Switch"), new("router", "Router"), new("printer", "Printer"), new("nas", "Storage"), new("desk1", "Desk 1"), new("desk2", "Desk 2"), new("desk3", "Desk 3"), new("spare", "Spare laptop") ]; private readonly ChartGraphLink[] _cables = [ new("switch", "router"), new("switch", "printer"), new("switch", "nas"), new("switch", "desk1"), new("switch", "desk2"), new("switch", "desk3") ]; ``` ## When to use Use a network diagram to show which nodes are connected. Only closeness carries meaning, not left, right, up or down, and the arrangement is the same every time for the same data. Links that name a missing node, or join a node to itself, are left out. ## Summary Tooltips and the table view give the source, target and value of each link. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwNetworkDiagramChart A network diagram: nodes drawn as dots and joined by a line for every link, arranged so that linked nodes sit close together and unrelated ones drift apart. | Parameter | Type | Description | | --- | --- | --- | | `Nodes` | `IReadOnlyList` | Gets or sets the nodes. Each needs a unique `Id`; repeats are left out. | | `Links` | `IReadOnlyList` | Gets or sets the links between nodes, by node identifier. Links that name a missing node, or join a node to itself, are left out. | | `SourceHeader` | `string?` | Gets or sets the heading of the column naming where each link starts in the table view. Defaults to the localized `Chart_Source` text ("Source"). | | `TargetHeader` | `string?` | Gets or sets the heading of the column naming where each link ends in the table view. Defaults to the localized `Chart_Destination` text ("Target"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels a link's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwNightingaleChart > TwNightingaleChart is a Blazor Nightingale (rose) chart: equal-angle wedges whose radius shows each value, suited to cyclical data. Documentation page: https://twblazor.com/chart/nightingale ## Basic usage `TwNightingaleChart` gives every value a wedge of the same angle and varies the radius. The area of each wedge is proportional to the value, so large values are not exaggerated. ```razor ``` ```csharp private readonly ChartValue[] _sources = [ new("Search", 430), new("Direct", 260), new("Social", 170), new("Email", 90), new("Referral", 50) ]; ``` ## Cyclical data The form suits values that follow a cycle, such as days of the week, where the last value sits beside the first. ```razor ``` ```csharp private readonly ChartValue[] _orders = [ new("Mon", 120), new("Tue", 135), new("Wed", 150), new("Thu", 170), new("Fri", 240), new("Sat", 310), new("Sun", 190) ]; ``` ## Many values As on a pie chart, past eight values the smallest are folded into one wedge named by `OtherLabel`. ## Summary Tooltips and the table view give the value of each wedge. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwNightingaleChart A Nightingale (rose) chart: equal-angle wedges whose radius shows each value, for comparing values that follow a cycle such as months. | Parameter | Type | Description | | --- | --- | --- | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwParallelCoordinatesChart > TwParallelCoordinatesChart is a Blazor parallel coordinates chart: one axis per variable and a line per item, each axis on its own scale. Documentation page: https://twblazor.com/chart/parallel-coordinates ## Basic usage `TwParallelCoordinatesChart` draws one vertical axis per variable and a line per item crossing each axis at its value. `Categories` are the variables and each series is one item. ```razor ``` ```csharp private readonly string[] _attributes = ["Battery", "Display", "Speed", "Weight", "Price"]; private readonly ChartSeries[] _laptops = [ new("Aero 13", [9, 7, 6, 9, 5]), new("Titan 16", [5, 9, 9, 4, 6]) ]; ``` ## Different units Every axis has its own scale, labelled with its lowest and highest value, so variables in different units can sit side by side. ```razor ``` ```csharp private readonly string[] _specs = ["Price (£k)", "Range (miles)", "0-60 (s)", "Boot (litres)"]; private readonly ChartSeries[] _cars = [ new("Volt", [32, 250, 7.9, 380]), new("Halo", [45, 330, 5.6, 420]), new("Dash", [27, 190, 9.4, 310]) ]; ``` ## Reading it Lines that run in parallel between two axes mean the variables rise together. Lines that cross mean one rises as the other falls. ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwParallelCoordinatesChart A parallel coordinates chart: one vertical axis per variable, with a line per item crossing each axis at its value, for comparing items across several variables at once. | Parameter | Type | Description | | --- | --- | --- | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwPieChart > TwPieChart is a Blazor pie chart for parts of a whole. Set an inner radius for a donut chart, or draw it as a semicircle. Documentation page: https://twblazor.com/chart/pie ## Basic usage `TwPieChart` sizes each slice by its share of the whole. Pass a list of `ChartValue`. Slices large enough to hold a label show their share, and the legend names every slice. ```razor ``` ```csharp private readonly ChartValue[] _sources = [ new("Search", 430), new("Direct", 260), new("Social", 170), new("Email", 90), new("Referral", 50) ]; ``` ## Donut Set `InnerRadius` between 0 and 0.9 to open a hole in the middle, and `CenterText` to put a headline figure in it. ```razor ``` ## Semicircle Set `Semicircle` for a half donut, which takes less vertical space. ```razor ``` ## Many values A pie works for a handful of parts. Past eight values, the smallest are folded into one slice named by `OtherLabel` so a color is never reused. The table view still lists every value. ```razor ``` ```csharp private readonly ChartValue[] _countries = [ new("United Kingdom", 320), new("United States", 280), new("Germany", 150), new("France", 120), new("Spain", 90), new("Italy", 70), new("Canada", 60), new("Japan", 40), new("Brazil", 30), new("India", 20) ]; ``` ## Labels `ShowPercentages` turns the share labels off. `LabelHeader` and `ValueHeader` name the table columns, and `ValueHeader` also names the value in tooltips. ## Summary Tooltips and the table view give the value of each slice. Tooltips also give its share of the whole. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwPieChart A pie chart: slices of a circle sized by each value's share of the whole. Set `InnerRadius` for a donut chart and `Semicircle` for a half donut. | Parameter | Type | Description | | --- | --- | --- | | `InnerRadius` | `double` | Gets or sets the size of the hole in the middle, as a fraction of the radius from 0 (a pie) to 0.9. | | `Semicircle` | `bool` | Gets or sets whether the chart is drawn as a half circle. | | `ShowPercentages` | `bool` | Gets or sets whether slices large enough to hold a label show their share. | | `CenterText` | `string?` | Gets or sets text shown in the hole of a donut, for example the total. | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwQuadrantChart > TwQuadrantChart is a Blazor quadrant chart: a scatter plot split into four labelled regions by two thresholds, for sorting items into groups. Documentation page: https://twblazor.com/chart/quadrant ## Basic usage `TwQuadrantChart` is a scatter plot divided into four regions by a horizontal and a vertical line. Points are labelled by default, since the reader wants to know which item landed where. ```razor ``` ```csharp private readonly ChartPointSeries[] _backlog = [ new("Features", [new(2, 8, "Search"), new(8, 9, "Billing"), new(3, 3, "Themes"), new(7, 2, "Importer"), new(4, 6, "Exports")]) ]; ``` ## Quadrant labels Name each region with `TopLeftLabel`, `TopRightLabel`, `BottomLeftLabel` and `BottomRightLabel`. ```razor ``` ## Thresholds The dividers sit in the middle of each axis unless you set `XThreshold` and `YThreshold` to the values that separate the groups. ```razor ``` ## Inherited options Everything on [TwScatterChart](https://twblazor.com/chart/scatter.md) is available, including bubble sizes and `ShowLabels`. ## Summary Tooltips and the table view give the X and Y values of each point, and its size when it has one. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwQuadrantChart A quadrant chart: a scatter plot divided into four labelled regions by a horizontal and a vertical threshold, for sorting items into groups such as "quick wins" and "major projects". | Parameter | Type | Description | | --- | --- | --- | | `XThreshold` | `double?` | Gets or sets the X value of the vertical divider. | | `YThreshold` | `double?` | Gets or sets the Y value of the horizontal divider. | | `TopLeftLabel` | `string?` | Gets or sets the label of the top-left quadrant. | | `TopRightLabel` | `string?` | Gets or sets the label of the top-right quadrant. | | `BottomLeftLabel` | `string?` | Gets or sets the label of the bottom-left quadrant. | | `BottomRightLabel` | `string?` | Gets or sets the label of the bottom-right quadrant. | | `Series` | `IReadOnlyList` | Gets or sets the series of points to plot. | | `XTitle` | `string` | Gets or sets the title of the horizontal axis. It also labels the X value in tooltips and the table view. | | `YTitle` | `string` | Gets or sets the title of the vertical axis. It also labels the Y value in tooltips and the table view. | | `SizeTitle` | `string?` | Gets or sets the label for a point's size in tooltips and the table view. Defaults to the localized `Chart_Size` text ("Size"). | | `Connect` | `bool` | Gets or sets whether the points of each series are joined in order (a connected scatter plot). | | `ShowLabels` | `bool` | Gets or sets whether each point that has a `Label` shows it beside the dot. | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwRadarChart > TwRadarChart is a Blazor radar (spider) chart that compares a few items across several attributes on spokes around a center. Documentation page: https://twblazor.com/chart/radar ## Basic usage `TwRadarChart` gives each category a spoke around a center and draws each series as a shape joining its values. It needs at least three categories. All spokes share one scale starting at zero, so use values in the same unit, such as scores. ```razor ``` ```csharp private readonly string[] _attributes = ["Battery", "Display", "Speed", "Weight", "Price"]; private readonly ChartSeries[] _laptops = [ new("Aero 13", [9, 7, 6, 9, 5]), new("Titan 16", [5, 9, 9, 4, 6]) ]; ``` ## Single series With one series the chart shows a profile: where an item is strong and where it is weak. ```razor ``` ```csharp private readonly ChartSeries[] _aero = [new("Aero 13", [9, 7, 6, 9, 5])]; ``` ## Size Radial charts are square. `Height` sets how wide the square may grow. ```razor ``` ## When to use Keep to two or three series, because overlapping shapes hide each other. For attributes in different units use [TwParallelCoordinatesChart](https://twblazor.com/chart/parallel-coordinates.md), which gives each its own scale. ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRadarChart A radar chart: one spoke per category around a center, with each series drawn as a shape joining its values, for comparing a few items across several attributes. | Parameter | Type | Description | | --- | --- | --- | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwRadialBarChart > TwRadialBarChart is a Blazor radial bar chart: bars bent around a circle, one ring per value, each sweeping further for larger values. Documentation page: https://twblazor.com/chart/radial-bar ## Basic usage `TwRadialBarChart` bends each bar around a circle, one ring per value, over a track that shows the full scale. Labels sit at the start of each ring. ```razor ``` ```csharp private readonly ChartValue[] _sources = [ new("Search", 430), new("Direct", 260), new("Social", 170), new("Email", 90), new("Referral", 50) ]; ``` ## Progress towards a goal With values on a common scale, such as percentages, the rings read as progress. ```razor ``` ```csharp private readonly ChartValue[] _progress = [ new("Basics", 100), new("Layouts", 80), new("Forms", 55), new("Testing", 20) ]; ``` ## When to use Outer rings are longer than inner rings for the same value, so read the angle swept, not the length. For precise comparison use [TwBarChart](https://twblazor.com/chart/bar.md). ## Summary Tooltips and the table view give the value of each ring. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRadialBarChart A radial bar chart: bars bent around a circle, one ring per value, each sweeping further the larger its value. | Parameter | Type | Description | | --- | --- | --- | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwRadialHistogramChart > TwRadialHistogramChart is a Blazor radial histogram that wraps equal-width bins around a circle, for cyclical values such as hours or bearings. Documentation page: https://twblazor.com/chart/radial-histogram ## Basic usage `TwRadialHistogramChart` takes raw `Values`, groups them into equal ranges and wraps the bars around a circle starting at the top. It suits values that cycle, where the last range sits naturally beside the first. ```razor ``` ```csharp private readonly double[] _ticketHours = [ 0.5, 2.2, 6.8, 7.4, 8.1, 8.3, 8.6, 9.0, 9.1, 9.2, 9.4, 9.7, 9.9, 10.1, 10.3, 10.4, 10.8, 11.2, 11.5, 11.9, 12.6, 13.1, 13.3, 13.8, 14.0, 14.2, 14.5, 14.9, 15.3, 15.6, 16.1, 16.4, 16.9, 17.5, 18.2, 19.6, 21.3, 23.9 ]; ``` ## Choosing the bins `BinCount` sets how many ranges the values are split into, from 4 to 36. Match it to the cycle: 24 for hours of the day, 12 for months, 8 or 16 for compass points. ```razor ``` ## Directions Bearings are the classic use: with eight bins each bar is a compass sector, north at the top. ```razor ``` ```csharp private readonly double[] _bearings = [ 0, 12, 198, 205, 211, 214, 219, 222, 225, 228, 230, 233, 236, 240, 244, 247, 251, 255, 262, 268, 271, 276, 284, 291, 302, 315, 334, 48, 95, 172, 186, 359.9 ]; ``` ## When to use Use a radial histogram for values that cycle, such as hours or bearings. Bars grow from an inner ring so small counts stay visible. For values that do not wrap around, prefer [TwHistogramChart](https://twblazor.com/chart/histogram.md), whose bars are easier to compare. ## Summary Tooltips and the table view give the range and count of each bin. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRadialHistogramChart A radial histogram: the values are grouped into equal ranges that wrap around a circle, each bar reaching further out the more values fall in its range. It suits cyclical data such as hours of the day or compass bearings. | Parameter | Type | Description | | --- | --- | --- | | `Values` | `IReadOnlyList` | Gets or sets the raw observations to group. | | `BinCount` | `int` | Gets or sets how many bins to group the values into, from 4 to 36. | | `RangeLabel` | `string?` | Gets or sets the label for a bin's range in the table view. Defaults to the localized `Chart_Range` text ("Range"). | | `CountLabel` | `string?` | Gets or sets the label for a bin's count in tooltips and the table view. Defaults to the localized `Chart_Count` text ("Count"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwRangeChart > TwRangeChart is a Blazor range chart that draws a floating bar from a low value to a high value per category, such as salary bands. Documentation page: https://twblazor.com/chart/range ## Basic usage `TwRangeChart` draws a floating bar from a low value to a high value for each category. Pass a list of `ChartRange`, each with a label, a low and a high. ```razor ``` ```csharp private readonly ChartRange[] _salaryBands = [ new("Junior", 28, 38), new("Mid", 36, 52), new("Senior", 50, 72), new("Lead", 65, 90) ]; ``` ## Vertical Set `Vertical` to stand the bars up, which suits ranges over time such as daily temperatures. ```razor ``` ```csharp private readonly ChartRange[] _temperatures = [ new("Mon", 8, 15), new("Tue", 9, 17), new("Wed", 11, 19), new("Thu", 7, 14), new("Fri", 6, 12) ]; ``` ## Labels `LowLabel` and `HighLabel` name the two ends in tooltips and the table view, and `LabelHeader` names the first table column. ## Summary Tooltips and the table view give the low and high value of each range. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRangeChart A range chart: a floating bar from a low value to a high value for each category, such as a temperature range or a salary band. | Parameter | Type | Description | | --- | --- | --- | | `Ranges` | `IReadOnlyList` | Gets or sets the ranges to plot. | | `Vertical` | `bool` | Gets or sets whether categories run left to right with values bottom to top, instead of the default rows with values left to right. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `LowLabel` | `string?` | Gets or sets the label for the low end of a range. Defaults to the localized `Chart_Low` text ("Low"). | | `HighLabel` | `string?` | Gets or sets the label for the high end of a range. Defaults to the localized `Chart_High` text ("High"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwRidgelinePlotChart > TwRidgelinePlotChart is a Blazor ridgeline plot that gives each group its own row and density curve, for comparing many distributions. Documentation page: https://twblazor.com/chart/ridgeline ## Basic usage `TwRidgelinePlotChart` draws one density curve per `ChartSample`, each on its own row with its name on the axis. Where a density plot overlays its curves, a ridgeline keeps them apart, so it copes with many more groups. ```razor ``` ```csharp private readonly ChartSample[] _deliveries = [ new("January", [3, 4, 4, 5, 5, 5, 6, 6, 7, 8, 9]), new("February", [2, 3, 3, 4, 4, 4, 5, 5, 6, 7]), new("March", [1, 2, 2, 2, 3, 3, 3, 4, 4, 5]) ]; ``` ## Many groups Order the groups so a drift is easy to follow. Here the daily temperature shifts up and back down across the year. A larger `Height` gives each ridge more room. ```razor ``` ```csharp private readonly ChartSample[] _temperatures = [ new("Jan", [4, 5, 6, 6, 7, 8, 8, 9, 10, 11]), new("Mar", [7, 8, 9, 10, 10, 11, 12, 13, 14, 15]), new("May", [13, 14, 15, 16, 17, 17, 18, 19, 20, 22]), new("Jul", [18, 20, 21, 22, 23, 23, 24, 25, 27, 30]), new("Sep", [14, 16, 17, 18, 18, 19, 20, 21, 22, 24]), new("Nov", [6, 7, 8, 9, 9, 10, 11, 12, 13, 14]) ]; ``` ## Side by side Groups are listed top to bottom by default. Set `Horizontal` to `false` to stand the ridges side by side with values running up the plot. ```razor ``` ## When to use Use a ridgeline plot to compare the shape of many distributions. Each ridge is scaled to the height of its own row, so compare where the ridges sit and how wide they are, not how tall. For two or three groups, [TwDensityPlotChart](https://twblazor.com/chart/density-plot.md) puts them on one scale. ## Summary Tooltips and the table view give the count, minimum, lower quartile, median, upper quartile and maximum of each group. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRidgelinePlotChart A ridgeline plot: one density curve per group, each on its own row, for comparing the shape of many distributions without the curves hiding one another. | Parameter | Type | Description | | --- | --- | --- | | `Samples` | `IReadOnlyList` | Gets or sets the groups of raw observations to plot. | | `Horizontal` | `bool` | Gets or sets whether groups are listed top to bottom with values running left to right. | | `LabelHeader` | `string?` | Gets or sets the heading of the group column in the table view. Defaults to the localized `Chart_Group` text ("Group"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwSankeyChart > TwSankeyChart is a Blazor Sankey diagram: nodes in columns joined by ribbons as thick as the flow between them. Documentation page: https://twblazor.com/chart/sankey ## Basic usage `TwSankeyChart` arranges `ChartGraphNode` values in columns and joins them with a ribbon for every `ChartGraphLink`, as thick as its value. A node sits to the right of every node that flows into it, and is as tall as what flows through it. Links refer to nodes by `Id`. ```razor ``` ```csharp private readonly ChartGraphNode[] _energyNodes = [ new("solar", "Solar"), new("wind", "Wind"), new("gas", "Gas"), new("grid", "Grid"), new("homes", "Homes"), new("industry", "Industry") ]; private readonly ChartGraphLink[] _energyLinks = [ new("solar", "grid", 25), new("wind", "grid", 40), new("gas", "grid", 35), new("grid", "homes", 45), new("grid", "industry", 55) ]; ``` ## Several stages Columns are worked out from the links, so a longer chain simply adds columns. This budget splits income into categories and then into line items, with everything it does not spend flowing to savings. ```razor ``` ```csharp private readonly ChartGraphNode[] _budgetNodes = [ new("salary", "Salary"), new("bonus", "Bonus"), new("income", "Income"), new("housing", "Housing"), new("living", "Living"), new("savings", "Savings"), new("rent", "Rent"), new("energy", "Energy"), new("food", "Food"), new("travel", "Travel"), new("leisure", "Leisure") ]; private readonly ChartGraphLink[] _budgetLinks = [ new("salary", "income", 3200), new("bonus", "income", 400), new("income", "housing", 1400), new("income", "living", 1300), new("income", "savings", 900), new("housing", "rent", 1150), new("housing", "energy", 250), new("living", "food", 520), new("living", "travel", 340), new("living", "leisure", 440) ]; ``` ## Setting the column A node with nothing flowing into it starts in the first column. Set its `Stage` to move it further right, as with the visitors who join this funnel at the basket from a saved link. ```razor ``` ```csharp private readonly ChartGraphNode[] _funnelNodes = [ new("home", "Home page"), new("product", "Product page"), new("saved", "Saved link", Stage: 1), new("basket", "Basket"), new("paid", "Paid"), new("left", "Abandoned") ]; private readonly ChartGraphLink[] _funnelLinks = [ new("home", "product", 5200), new("product", "basket", 1900), new("saved", "basket", 600), new("basket", "paid", 1400), new("basket", "left", 1100) ]; ``` ## When to use Use a Sankey diagram to show how a quantity divides and recombines as it moves through stages. Links without a positive value are left out. ## Summary Tooltips and the table view give the source, target and value of each link. Tooltips also give the total of each node. The arrow keys visit the nodes first, then the links. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSankeyChart A Sankey diagram: nodes in columns joined by ribbons as thick as the flow between them, for showing how a quantity divides and recombines as it moves through stages. | Parameter | Type | Description | | --- | --- | --- | | `Nodes` | `IReadOnlyList` | Gets or sets the nodes. Each needs a unique `Id`; repeats are left out. | | `Links` | `IReadOnlyList` | Gets or sets the links between nodes, by node identifier. Links that name a missing node, or join a node to itself, are left out. | | `SourceHeader` | `string?` | Gets or sets the heading of the column naming where each link starts in the table view. Defaults to the localized `Chart_Source` text ("Source"). | | `TargetHeader` | `string?` | Gets or sets the heading of the column naming where each link ends in the table view. Defaults to the localized `Chart_Destination` text ("Target"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels a link's value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwScatterChart > TwScatterChart is a Blazor scatter plot that positions points by two values. Also draws bubble charts and connected scatter plots. Documentation page: https://twblazor.com/chart/scatter ## Basic usage `TwScatterChart` positions points by two numeric values to show how they relate. Pass one or more `ChartPointSeries`, each a named list of `ChartPoint`. `XTitle` and `YTitle` label the axes and name the values in tooltips and the table view. ```razor ``` ```csharp private readonly ChartPointSeries[] _products = [ new("Audio", [new(49, 4.1, "Buds"), new(129, 4.6, "Studio"), new(79, 3.8, "Sport")]), new("Wearables", [new(199, 4.4, "Pulse"), new(99, 3.6, "Band"), new(249, 4.7, "Pro")]) ]; ``` ## Bubble chart Give points a `Size` and each is drawn as a bubble whose area follows it, adding a third value. `SizeTitle` names it. ```razor ``` ```csharp private readonly ChartPointSeries[] _bubbles = [ new("Audio", [new(49, 4.1, "Buds", 320), new(129, 4.6, "Studio", 180), new(79, 3.8, "Sport", 240)]), new("Wearables", [new(199, 4.4, "Pulse", 150), new(99, 3.6, "Band", 410), new(249, 4.7, "Pro", 90)]) ]; ``` ## Point labels Set `ShowLabels` to print each point's `Label` beside it. ```razor ``` ## Connected scatter plot Set `Connect` to join the points of each series in order, tracing a path through two variables over time. ```razor ``` ```csharp private readonly ChartPointSeries[] _economy = [ new("Economy", [new(4.1, 2.0, "2021"), new(3.8, 6.2, "2022"), new(4.3, 7.4, "2023"), new(4.6, 3.1, "2024"), new(4.4, 2.4, "2025")]) ]; ``` ## Colors Any two points can sit side by side, so keep to three series or fewer for colors that stay easy to tell apart. ## Summary Tooltips and the table view give the X and Y values of each point, and its size when it has one. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwScatterChart A scatter plot: points positioned by two numeric values to show how they relate. Give points a `Size` for a bubble chart, or set `Connect` for a connected scatter plot. | Parameter | Type | Description | | --- | --- | --- | | `Series` | `IReadOnlyList` | Gets or sets the series of points to plot. | | `XTitle` | `string` | Gets or sets the title of the horizontal axis. It also labels the X value in tooltips and the table view. | | `YTitle` | `string` | Gets or sets the title of the vertical axis. It also labels the Y value in tooltips and the table view. | | `SizeTitle` | `string?` | Gets or sets the label for a point's size in tooltips and the table view. Defaults to the localized `Chart_Size` text ("Size"). | | `Connect` | `bool` | Gets or sets whether the points of each series are joined in order (a connected scatter plot). | | `ShowLabels` | `bool` | Gets or sets whether each point that has a `Label` shows it beside the dot. | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwSlopeChart > TwSlopeChart is a Blazor slope chart: a labelled line per series between two points in time, showing the direction and size of each change. Documentation page: https://twblazor.com/chart/slope ## Basic usage `TwSlopeChart` draws a straight line per series between two points in time and labels both ends, so the direction and size of each change is read from the slope. Use two categories for the classic form. ```razor ``` ```csharp private readonly string[] _years = ["2020", "2025"]; private readonly ChartSeries[] _share = [ new("Aster", [34, 41]), new("Birch", [28, 19]), new("Cedar", [15, 26]) ]; ``` ## More than two points Extra categories add intermediate points. The first is labelled with the series name and value, and the last with its value. ```razor ``` ```csharp private readonly string[] _threeYears = ["2015", "2020", "2025"]; private readonly ChartSeries[] _shareByYear = [ new("Aster", [22, 34, 41]), new("Birch", [37, 28, 19]), new("Cedar", [9, 15, 26]) ]; ``` ## Formatting `ValueFormat` applies to the end labels as well as the tooltips and table view. ```razor ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSlopeChart A slope chart: a straight line per series between two (or a few) points in time, labelled at both ends, so the direction and size of each change is read from the slope. | Parameter | Type | Description | | --- | --- | --- | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwSmallMultiplesChart > TwSmallMultiplesChart is a Blazor small multiples chart: one small panel per series on a shared scale, for comparing many series clearly. Documentation page: https://twblazor.com/chart/small-multiples ## Basic usage `TwSmallMultiplesChart` repeats one simple chart per series, all on one shared scale so the panels can be compared at a glance. Reach for it when a single plot would hold too many series to tell apart. ```razor ``` ```csharp private readonly string[] _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; private readonly ChartSeries[] _visitors = [ new("Organic", [42, 48, 55, 61, 58, 70]), new("Paid", [30, 34, 31, 45, 52, 49]), new("Referral", [12, 15, 21, 19, 26, 33]) ]; ``` ## Kind `Kind` picks the mark drawn in each panel: `SmallMultipleKind.Column` (the default), `Line` or `Area`. ```razor ``` ```razor ``` ## Columns Up to three panels share a row. Set `Columns` to change that, and `Height` to give several rows more room. ```razor ``` ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSmallMultiplesChart Small multiples: the same simple chart repeated in a grid, one panel per series, all on one shared scale so the panels can be compared at a glance. Use it instead of crowding many series into one plot. | Parameter | Type | Description | | --- | --- | --- | | `Kind` | `SmallMultipleKind` | Gets or sets the mark drawn in each panel: columns, a line or an area. | | `Columns` | `int?` | Gets or sets how many panels sit in a row. | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwStreamGraphChart > TwStreamGraphChart is a Blazor stream graph: stacked layers that flow around a central line to show how the make-up of a total shifts over time. Documentation page: https://twblazor.com/chart/stream-graph ## Basic usage `TwStreamGraphChart` stacks one smooth layer per series around the middle of the plot instead of on a baseline. The thickness of a layer is its value, and the outline of the whole stream is the total. ```razor ``` ```csharp private readonly string[] _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]; private readonly ChartSeries[] _sources = [ new("Search", [24, 28, 26, 34, 38, 41]), new("Direct", [16, 18, 22, 20, 19, 23]), new("Social", [10, 14, 12, 18, 27, 22]) ]; ``` ## Rise and fall A stream graph is at its best when series come and go. Here each genre swells and fades in turn, which a stacked area chart would bury under a climbing baseline. ```razor ``` ```csharp private readonly string[] _years = ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"]; private readonly ChartSeries[] _genres = [ new("Rock", [42, 40, 36, 31, 27, 24, 22, 20, 19, 18]), new("Pop", [35, 38, 44, 48, 46, 41, 37, 35, 34, 33]), new("Hip hop", [12, 18, 27, 36, 45, 52, 50, 44, 39, 36]), new("Electronic", [8, 9, 11, 15, 22, 31, 40, 46, 43, 38]), new("Podcasts", [0, 1, 3, 6, 12, 20, 29, 37, 48, 58]) ]; ``` ## Hiding layers Click a legend entry to remove its layer; the rest close up around the middle. Set `InteractiveLegend` to `false` to keep every layer in place. ```razor ``` ## When to use Use a stream graph for the changing make-up of a total. Only thickness carries meaning; a layer's height on the plot does not. Missing and negative values count as zero. When exact totals matter, use a stacked [TwAreaChart](https://twblazor.com/chart/area.md). ## Summary Tooltips and the table view give the value of every series for each category. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwStreamGraphChart A stream graph: a stacked area chart whose layers flow around a central line instead of rising from a baseline, emphasising how the make-up of a total shifts over time. | Parameter | Type | Description | | --- | --- | --- | | `Categories` | `IReadOnlyList` | Gets or sets the category labels, in order. | | `Series` | `IReadOnlyList` | Gets or sets the series to plot. Each holds one value per category. | | `CategoryHeader` | `string?` | Gets or sets the heading of the category column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwStripPlotChart > TwStripPlotChart is a Blazor strip plot that draws every observation as a dot, one strip per group. Add jitter to separate overlaps. Documentation page: https://twblazor.com/chart/strip-plot ## Basic usage `TwStripPlotChart` draws every observation in a `ChartSample` as a dot along the value axis, one strip per group, so the raw spread and any clusters are visible. ```razor ``` ```csharp private readonly ChartSample[] _services = [ new("Search", [112, 120, 131, 135, 138, 142, 144, 149, 151, 153, 290]), new("Checkout", [156, 158, 160, 163, 167, 170, 172, 176, 181, 185]), new("Reports", [190, 196, 204, 215, 228, 240, 262, 150, 310]) ]; ``` ## Jitter Set `Jitter` to nudge dots sideways so overlapping values stay visible. The nudge is repeatable: the same data always draws the same picture. ```razor ``` ## Horizontal Set `Horizontal` to list the groups down the side. ```razor ``` ## When to use A strip plot suits small samples. For large ones, summarise with [TwBoxPlotChart](https://twblazor.com/chart/box-plot.md) or [TwHistogramChart](https://twblazor.com/chart/histogram.md). ## Summary Tooltips and the table view give the count, minimum, lower quartile, median, upper quartile and maximum of each group. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwStripPlotChart A strip plot: every observation drawn as a dot along the value axis, one strip per group, so the raw spread and any clusters are visible. Set `Jitter` to spread overlapping dots sideways (a jitter plot). | Parameter | Type | Description | | --- | --- | --- | | `Jitter` | `bool` | Gets or sets whether dots are nudged sideways by a small, repeatable amount so overlapping values stay visible. | | `Samples` | `IReadOnlyList` | Gets or sets the groups of raw observations to plot. | | `Horizontal` | `bool` | Gets or sets whether groups are listed top to bottom with values running left to right. | | `LabelHeader` | `string?` | Gets or sets the heading of the group column in the table view. Defaults to the localized `Chart_Group` text ("Group"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwSunburstChart > TwSunburstChart is a Blazor sunburst chart: a tree drawn as rings, each segment sized by its share of the whole. Documentation page: https://twblazor.com/chart/sunburst ## Basic usage `TwSunburstChart` draws a tree of `ChartHierarchyNode` values as rings. The top-level nodes form the inner ring and each node's children sit around it in the next ring out, every segment sized by its share of the whole. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _sales = [ new("North", Children: [new("Hardware", 38), new("Software", 24)]), new("South", Children: [new("Hardware", 28), new("Software", 16)]) ]; ``` ## Three rings Each top-level node has its own color and its descendants are lighter tints of it, so a branch reads as one family all the way out. A larger `Height` leaves more segments room for their names. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _visits = [ new("Search", Children: [ new("Organic", Children: [new("Mobile", 4200), new("Desktop", 3100)]), new("Paid", Children: [new("Mobile", 1800), new("Desktop", 900)]) ]), new("Social", Children: [ new("Video", Children: [new("Mobile", 2600), new("Desktop", 400)]), new("Posts", Children: [new("Mobile", 1500), new("Desktop", 700)]) ]), new("Direct", Children: [new("Mobile", 1900), new("Desktop", 2400)]) ]; ``` ## Uneven branches Branches need not be the same depth. A node without children simply ends at its own ring, leaving the rings beyond it empty. ```razor ``` ```csharp private readonly ChartHierarchyNode[] _spending = [ new("Housing", Children: [new("Rent", 1150), new("Energy", 180), new("Water", 45)]), new("Food", Children: [new("Groceries", 420), new("Eating out", Children: [new("Lunches", 90), new("Dinners", 140)])]), new("Transport", Children: [new("Rail", 210), new("Car", 130)]), new("Savings", 400) ]; ``` ## When to use Use a sunburst chart to show shares at every level of a tree. Names that do not fit are cut short or left off. Nodes with no value are left out. ## Summary Tooltips and the table view give the path and the value of each segment. Tooltips also give its share of the whole. The arrow keys visit a segment, then its children, then the next segment. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSunburstChart A sunburst chart: a tree drawn as rings, with the top-level nodes in the middle and each node's children around it, every segment sized by its share of the whole. | Parameter | Type | Description | | --- | --- | --- | | `Roots` | `IReadOnlyList` | Gets or sets the top-level nodes of the tree. | | `LabelHeader` | `string?` | Gets or sets the heading of the node column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwTreemapChart > TwTreemapChart is a Blazor treemap: rectangles that tile the plot, each sized by its value, showing many parts of a whole compactly. Documentation page: https://twblazor.com/chart/treemap ## Basic usage `TwTreemapChart` tiles the plot with rectangles sized by value. Tiles are laid out largest first and kept close to square so their areas are easy to compare. Tiles with room show their label; every tile has a tooltip. ```razor ``` ```csharp private readonly ChartValue[] _sources = [ new("Search", 430), new("Direct", 260), new("Social", 170), new("Email", 90), new("Referral", 50) ]; ``` ## Many values A treemap copes with far more parts than a pie, which makes it a good fit for long-tailed data. ```razor ``` ```csharp private readonly ChartValue[] _folders = [ new("Videos", 180), new("Photos", 120), new("Projects", 75), new("Music", 48), new("Documents", 30), new("Downloads", 22), new("Backups", 16), new("Apps", 12), new("Fonts", 5), new("Temp", 3) ]; ``` ## Values Negative and zero values have no area, so they are left out of the plot. They still appear in the table view. ## Summary Tooltips and the table view give the value of each tile. Tooltips also give its share of the whole. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwTreemapChart A treemap: rectangles that tile the plot, each sized by its value, for showing many parts of a whole in a compact space. | Parameter | Type | Description | | --- | --- | --- | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwVennDiagramChart > TwVennDiagramChart is a Blazor Venn diagram: up to three sets as equal overlapping circles, with the shared count where each pair meets. Documentation page: https://twblazor.com/chart/venn-diagram ## Basic usage `TwVennDiagramChart` draws each `ChartSet` as a circle and overlaps them all. A `ChartSetIntersection` names two sets and how many elements they share; that number is written where the two circles meet. ```razor ``` ```csharp private readonly ChartSet[] _skills = [new("Research", 38), new("Design", 32), new("Engineering", 44)]; private readonly ChartSetIntersection[] _sharedSkills = [ new("Research", "Design", 14), new("Design", "Engineering", 9), new("Research", "Engineering", 6) ]; ``` ## Two sets With two sets the circles sit side by side. Intersections can name their sets in either order. ```razor ``` ```csharp private readonly ChartSet[] _audiences = [new("Newsletter", 120), new("App", 85)]; private readonly ChartSetIntersection[] _sharedAudience = [new("App", "Newsletter", 40)]; ``` ## Missing overlaps A Venn diagram always draws every possible overlap. A pair with no intersection given still overlaps on the plot but shows no number. To draw only the overlaps that exist, with circles sized by their sets, use [TwEulerDiagramChart](https://twblazor.com/chart/euler-diagram.md). ```razor ``` ```csharp private readonly ChartSet[] _features = [new("Reports", 2400), new("Exports", 1100), new("Alerts", 860)]; private readonly ChartSetIntersection[] _sharedFeatures = [new("Reports", "Exports", 940), new("Reports", "Alerts", 310)]; ``` ## When to use Use a Venn diagram to show which sets overlap. The circles are all the same size, so read the numbers, not the areas. Up to three sets are drawn, and sets with no size are left out. To size the circles by their sets, use [TwEulerDiagramChart](https://twblazor.com/chart/euler-diagram.md). ## Summary Tooltips and the table view give the size of each set and of each overlap. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwVennDiagramChart A Venn diagram: up to three sets drawn as equal circles that all overlap, with the number of shared elements written where each pair meets. | Parameter | Type | Description | | --- | --- | --- | | `Sets` | `IReadOnlyList` | Gets or sets the sets to draw. Up to three are shown; sets with no size are left out. | | `Intersections` | `IReadOnlyList` | Gets or sets how many elements each pair of sets shares. Each is named by the labels of its two sets. | | `LabelHeader` | `string?` | Gets or sets the heading of the set column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the size column in the table view. It also labels a set's size in tooltips. Defaults to the localized `Chart_Size` text ("Size"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwViolinPlotChart > TwViolinPlotChart is a Blazor violin plot that shows the full shape of each group's distribution with its median and middle half marked. Documentation page: https://twblazor.com/chart/violin-plot ## Basic usage `TwViolinPlotChart` draws a mirrored density curve for each `ChartSample`: wide where values cluster, narrow where they are rare. The bar down the middle spans the middle half of the values and the dot marks the median. ```razor ``` ```csharp private readonly ChartSample[] _classes = [ new("Class A", [48, 55, 58, 61, 63, 64, 66, 67, 69, 71, 74, 78, 85]), new("Class B", [52, 60, 66, 70, 72, 74, 75, 76, 78, 80, 83, 88, 94]), new("Class C", [35, 42, 51, 57, 62, 68, 71, 77, 82, 86, 90]) ]; ``` ## Shapes a box plot hides These two teams have almost the same median and quartiles, so their box plots would look alike. The violins show that one is evenly spread while the other splits into a fast group and a slow group. ```razor ``` ```csharp private readonly ChartSample[] _teams = [ new("Evenly spread", [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]), new("Two groups", [2, 3, 3, 4, 4, 5, 20, 21, 21, 22, 23, 24]) ]; ``` ## Horizontal Set `Horizontal` to list the groups down the side, which suits long names and many groups. ```razor ``` ## When to use Use a violin plot when the shape of each distribution matters. Each violin is drawn to the full width of its slot and ends at the group's lowest and highest values, so compare the shapes, not the widths. For a plain summary use [TwBoxPlotChart](https://twblazor.com/chart/box-plot.md). ## Summary Tooltips and the table view give the count, minimum, lower quartile, median, upper quartile and maximum of each group. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwViolinPlotChart A violin plot: for each group, a mirrored density curve showing where its values concentrate, with a bar across the middle half of the values and a dot at the median. | Parameter | Type | Description | | --- | --- | --- | | `Samples` | `IReadOnlyList` | Gets or sets the groups of raw observations to plot. | | `Horizontal` | `bool` | Gets or sets whether groups are listed top to bottom with values running left to right. | | `LabelHeader` | `string?` | Gets or sets the heading of the group column in the table view. Defaults to the localized `Chart_Group` text ("Group"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwWaffleChart > TwWaffleChart is a Blazor waffle chart: a ten by ten grid of squares, each worth one percent, colored by each value's share. Documentation page: https://twblazor.com/chart/waffle ## Basic usage `TwWaffleChart` shows parts of a whole as a ten by ten grid where each square is one percent. Counting squares is easier than judging angles, so small differences read more reliably than on a pie. ```razor ``` ```csharp private readonly ChartValue[] _sources = [ new("Search", 430), new("Direct", 260), new("Social", 170), new("Email", 90), new("Referral", 50) ]; ``` ## Two parts It is at its clearest for a single share against the rest. ```razor ``` ```csharp private readonly ChartValue[] _responses = [ new("Responded", 62), new("No response", 38) ]; ``` ## Rounding Squares are shared out so the grid is always full, even when the shares do not round to whole percentages. The legend states each exact share. ## Summary Tooltips and the table view give the value of each category. Tooltips also give its share of the whole. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwWaffleChart A waffle chart: a ten by ten grid of squares, each worth one percent, colored by the share of each value. It shows parts of a whole in countable units, which is easier to read than angles. | Parameter | Type | Description | | --- | --- | --- | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwWaterfallChart > TwWaterfallChart is a Blazor waterfall chart: floating columns that show how increases and decreases build up to a total. Documentation page: https://twblazor.com/chart/waterfall ## Basic usage `TwWaterfallChart` shows how a series of changes builds up to a result. Each `ChartValue` in `Data` is a change, positive or negative, and each column floats from where the previous one ended. A total column is added for you. Direction is shown by color and named in the legend and tooltips, so it never depends on color alone. ```razor ``` ```csharp private readonly ChartValue[] _bridge = [ new("Sales", 520), new("Services", 140), new("Cost of goods", -210), new("Salaries", -180), new("Marketing", -60) ]; ``` ## Value labels Set `ShowValues` to label each column with its signed change. ```razor ``` ## Total and labels Set `ShowTotal` to `false` to leave out the final column. `TotalLabel`, `IncreaseLabel` and `DecreaseLabel` rename the legend entries. ```razor ``` ## Summary Tooltips and the table view give the change at each step. Tooltips also give the running total. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwWaterfallChart A waterfall chart: floating columns that show how a series of increases and decreases build up to a total. | Parameter | Type | Description | | --- | --- | --- | | `ShowTotal` | `bool` | Gets or sets whether a final column showing the running total is added. | | `TotalLabel` | `string?` | Gets or sets the label of the total column. Defaults to the localized `Chart_Total` text ("Total"). | | `IncreaseLabel` | `string?` | Gets or sets the legend label for positive changes. Defaults to the localized `Chart_Increase` text ("Increase"). | | `DecreaseLabel` | `string?` | Gets or sets the legend label for negative changes. Defaults to the localized `Chart_Decrease` text ("Decrease"). | | `ShowValues` | `bool` | Gets or sets whether each column is labelled with its change. | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwWordCloudChart > TwWordCloudChart is a Blazor word cloud: words sized by their values and gathered around the middle of the plot. Documentation page: https://twblazor.com/chart/word-cloud ## Basic usage `TwWordCloudChart` takes labelled values as `Data` and draws each label as a word sized by its value, with the largest in the middle. It gives a quick impression of which terms dominate. ```razor ``` ```csharp private readonly ChartValue[] _terms = [ new("pricing", 50), new("login", 38), new("invoice", 30), new("export", 24), new("api", 20), new("refund", 14), new("password", 12), new("teams", 9) ]; ``` ## Many words As words are added they all shrink together to fit. A larger `Height` gives them more room. Use `LabelHeader` and `ValueHeader` to name the columns of the table view; the value heading also labels tooltips. ```razor ``` ```csharp private readonly ChartValue[] _feedback = [ new("fast", 182), new("support", 164), new("easy", 151), new("price", 139), new("reliable", 118), new("dashboard", 104), new("setup", 96), new("mobile", 88), new("reports", 81), new("slow", 74), new("billing", 69), new("search", 63), new("helpful", 58), new("export", 52), new("confusing", 47), new("integration", 43), new("clean", 39), new("updates", 35), new("login", 31), new("onboarding", 28), new("charts", 25), new("filters", 22), new("alerts", 19), new("permissions", 17), new("sync", 15), new("templates", 13), new("offline", 11), new("shortcuts", 9), new("themes", 8), new("imports", 7) ]; ``` ## Compact At `ChartHeight.Small` the words are set smaller to match, which suits a card on a dashboard. ```razor ``` ```csharp private readonly ChartValue[] _tags = [ new("blazor", 40), new("tailwind", 32), new("charts", 21), new("a11y", 18), new("dotnet", 15), new("css", 9) ]; ``` ## When to use Use a word cloud for a quick impression, not for exact comparison. The area of a word, not its height, follows its value. When there are more words than fit, the smallest are left out of the plot, and negative and zero values are always left out. For exact comparison use [TwBarChart](https://twblazor.com/chart/bar.md). ## Summary Tooltips and the table view give the value of each word. The arrow keys step through the words from largest to smallest. ## Shared features The legend, tooltips, keyboard navigation, table view, value formatting, height and empty state work the same on every chart. See [TwChart](https://twblazor.com/chart.md) for those options. ## Keyboard navigation The plot is a single Tab stop. Each data point is announced with its series and value as focus reaches it, and the table view presents the same data without the plot. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the plot, onto the data point last visited. | | `Arrow Right` or `Arrow Down` | Moves to the next data point. | | `Arrow Left` or `Arrow Up` | Moves to the previous data point. | | `Home` or `End` | Moves to the first or last data point. | | `Escape` | Hides the tooltip of the focused data point. | | `Enter` or `Space` | On a legend item: shows or hides that series. On the table button: switches between the chart and its data table. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwWordCloudChart A word cloud: words sized by their values and gathered around the middle of the plot, for a quick impression of which terms dominate a body of text. | Parameter | Type | Description | | --- | --- | --- | | `Data` | `IReadOnlyList` | Gets or sets the values to plot. | | `LabelHeader` | `string?` | Gets or sets the heading of the label column in the table view. Defaults to the localized `Chart_Category` text ("Category"). | | `ValueHeader` | `string?` | Gets or sets the heading of the value column in the table view. It also labels the value in tooltips. Defaults to the localized `Chart_Value` text ("Value"). | | `OtherLabel` | `string?` | Gets or sets the label of the slice that collects the smallest values once there are more values than colors. Defaults to the localized `Chart_Other` text ("Other"). | | `Height` | `ChartHeight?` | Gets or sets the height of the plot area. | | `ShowLegend` | `bool` | Gets or sets whether the legend is shown when the chart has one. | | `InteractiveLegend` | `bool` | Gets or sets whether clicking a legend entry hides or shows its series. | | `ShowTableToggle` | `bool` | Gets or sets whether the button that switches between the plot and a table of the same data is shown. | | `TableViewLabel` | `string?` | Gets or sets the label of the button that switches to the table view. Defaults to the localized `Chart_ViewAsTable` text ("View as table"). | | `ChartViewLabel` | `string?` | Gets or sets the label of the button that switches back to the plot. Defaults to the localized `Chart_ViewAsChart` text ("View as chart"). | | `TableLabel` | `string?` | Gets or sets the accessible name of the table view. Defaults to the localized `Chart_TableLabel` text ("Chart data"). | | `LegendLabel` | `string?` | Gets or sets the accessible name of the legend. Defaults to the localized `Chart_Legend` text ("Legend"). | | `EmptyText` | `string?` | Gets or sets the message shown when there is no data to plot. Defaults to the localized `Chart_Empty` text ("No data to display"). | | `ValueFormat` | `string?` | Gets or sets the .NET numeric format string used for values on axes, tooltips and the table view, for example `"C0"` or `"0.0%"`. | | `ValueFormatter` | `Func?` | Gets or sets a function that formats values, for full control over units and abbreviations. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwCheckbox > TwCheckbox is a Blazor checkbox component. Bind Value or SelectedValues, set Color, Size, Disabled and Horizontal, or generate a group from Items. Documentation page: https://twblazor.com/checkbox ## Basic usage Group checkboxes with `TwCheckboxGroup` and bind individual values with `@bind-Value`. ```razor ``` ```csharp private bool sports = true; private bool music = false; private bool reading = true; private bool gaming = false; ``` ## Sizes Use `Size` to render a smaller or larger checkbox. Defaults to `Size.Md`, the original size. ```razor
``` ## Indeterminate state Bind a `TwCheckbox` and pass `null` to render it indeterminate - useful for a "select all" checkbox that reflects a partially-selected list below it. Clicking an indeterminate checkbox always resolves it to fully checked or unchecked; there's no click gesture that produces the indeterminate state itself. ```razor
``` ```csharp private bool apples = true; private bool bananas = false; private bool cherries = true; private bool? selectAllState => (apples, bananas, cherries) switch { (true, true, true) => true, (false, false, false) => false, _ => null }; private void OnSelectAllChanged(bool? value) { var newValue = value ?? false; apples = newValue; bananas = newValue; cherries = newValue; } ``` ## Colors Group checkboxes with `TwCheckboxGroup` and bind individual values with `@bind-Value`. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color)))) { @if (c != Color.Light && c != Color.Dark) {
} else {
} } ``` ## Data-driven (automatic) Use `Items` and `@bind-SelectedValues` to generate checkboxes from a list. ```razor

Selected: @string.Join(", ", selectedLanguages?.Select(l => l.ToString()) ?? Enumerable.Empty())

Enabled notifications:

    @foreach (var notif in selectedNotifications ?? Enumerable.Empty()) {
  • @notif
  • }
``` ```csharp public enum ProgrammingLanguage { CSharp, JavaScript, Python, TypeScript, Java } private readonly List> _languageItems = new() { new() { Label = "C#", Value = ProgrammingLanguage.CSharp, IsSelected = true }, new() { Label = "JavaScript", Value = ProgrammingLanguage.JavaScript, IsSelected = true }, new() { Label = "Python", Value = ProgrammingLanguage.Python, IsSelected = false }, new() { Label = "TypeScript", Value = ProgrammingLanguage.TypeScript, IsSelected = false }, new() { Label = "Java", Value = ProgrammingLanguage.Java, IsSelected = false } }; private IEnumerable? selectedLanguages = new[] { ProgrammingLanguage.CSharp, ProgrammingLanguage.JavaScript }; private readonly List> _notificationItems = new() { new() { Label = "Email notifications", Value = "Email", IsSelected = true }, new() { Label = "SMS notifications", Value = "SMS", IsSelected = false }, new() { Label = "Push notifications", Value = "Push", IsSelected = true } }; private IEnumerable? selectedNotifications = new[] { "Email", "Push" }; ``` ## Horizontal layout & custom spacing Use `Horizontal` to arrange checkboxes side-by-side, or `Spacing="4"` for custom spacing. ```razor
``` ```csharp private bool monday = true; private bool tuesday = true; private bool wednesday = false; private bool thursday = true; private bool friday = true; private bool agreeTerms = false; private bool agreePrivacy = false; private bool agreeNewsletter = false; ``` ## Disabled state Disable the entire group with the `Disabled` property. ```razor ``` ## Programmatic control Change selections programmatically by updating the bound collection. ```razor

Selected: @string.Join(", ", selectedDays ?? Enumerable.Empty())

``` ```csharp private readonly List> _dayItems = new() { new() { Label = "Monday", Value = DayOfWeek.Monday, IsSelected = false }, new() { Label = "Tuesday", Value = DayOfWeek.Tuesday, IsSelected = false }, new() { Label = "Wednesday", Value = DayOfWeek.Wednesday, IsSelected = false }, new() { Label = "Thursday", Value = DayOfWeek.Thursday, IsSelected = false }, new() { Label = "Friday", Value = DayOfWeek.Friday, IsSelected = false }, new() { Label = "Saturday", Value = DayOfWeek.Saturday, IsSelected = false }, new() { Label = "Sunday", Value = DayOfWeek.Sunday, IsSelected = false } }; private IEnumerable? selectedDays = Enumerable.Empty(); private void SelectWeekdays() { selectedDays = new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }; } private void SelectWeekend() { selectedDays = new[] { DayOfWeek.Saturday, DayOfWeek.Sunday }; } private void ClearDays() { selectedDays = Enumerable.Empty(); } ``` ## Keyboard navigation A checkbox is a native checkbox, so it behaves as one. A read-only checkbox can be focused but not changed. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the checkbox. | | `Space` | Checks or unchecks it. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCheckbox Represents a generic checkbox input component for Blazor that supports two-way data binding and customizable value types. | Parameter | Type | Description | | --- | --- | --- | | `Name` | `string` | Gets or sets the name associated with the component. | | `Color` | `Color?` | Gets or sets the color of the checkbox. | | `Size` | `Size` | Gets or sets the size of the checkbox and its check/dash icon. Defaults to `Md`, the same dimensions this component has always rendered at. | | `Value` | `T` | Gets or sets the current value of the parameter. | | `ValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the value changes. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwCheckboxGroup Represents a container component for grouping multiple `TwCheckbox` components together. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the content to display within the checkbox group. | | `Legend` | `string?` | Gets or sets the legend text for the checkbox group. | | `LegendClass` | `string?` | Gets or sets the CSS class for the legend element. | | `Horizontal` | `bool` | Gets or sets the orientation of the checkbox group. | | `Disabled` | `bool` | Gets or sets whether the entire checkbox group is disabled. | | `Name` | `string?` | Gets or sets the name for all checkboxes in the group. | | `Items` | `IEnumerable>?` | Gets or sets the collection of items to display as checkboxes (for automatic mode). | | `SelectedValues` | `IEnumerable?` | Gets or sets the collection of selected values (for automatic mode with Items). | | `SelectedValuesChanged` | `EventCallback>` | Gets or sets the callback invoked when the selected values change (for automatic mode with Items). | | `ItemColor` | `Color?` | Gets or sets the color for automatically generated checkboxes. | | `Invalid` | `bool` | Gets or sets whether the group as a whole is in an error state. | | `ErrorMessage` | `string` | Gets or sets the error message for the group. It is shown under the options when `Invalid` is set, announced when it appears, and read as the group's description. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwCheckboxTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwCheckboxTheme` by hand. --- # TwChip > TwChip is a Blazor chip component for tags and filters. Set Label, Color, Variant, Size, StartIcon, Avatar and Href, or make it Closable with OnClose. Documentation page: https://twblazor.com/chip ## Basic usage Group chips with `TwChipGroup` for automatic wrapping and layout. ```razor ``` ## Sizes Use `Size` to render a smaller or larger chip. Defaults to `ChipSize.Medium`. ```razor ``` ## Colors Group chips with `TwChipGroup` for automatic wrapping and layout. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color))).Take(10)) { @if (c != Color.Light && c != Color.Dark) {
} else {
}
} ``` ## Closable chips Use `Closable` and `OnClose` to create removable tags. ```razor @foreach (var tag in _tags) { } ``` ```csharp private readonly List _tags = new() { "JavaScript", "TypeScript", "React", "Node.js", "MongoDB" }; private void RemoveTag(string tag) { _tags.Remove(tag); } ``` ## Alignment & spacing Control alignment with `Alignment` and adjust spacing with `Class="gap-*"`. ```razor

Center aligned with custom spacing

End aligned with tight spacing

``` ## With icons & variants Add icons with `StartIcon`/`EndIcon` and use different variants for various use cases. ```razor

Skills with start icons

Actions with end icons

Status indicators

``` ## With avatars Use the `Avatar` property to display initials or text at the start of the chip. ```razor ``` ## Link chips Use `Href` to make chips navigable. Use `Target` for external links. ```razor ``` ## Disabled state Use the `Disabled` property to make chips non-interactive. ```razor ``` ## Keyboard navigation A plain chip is not a Tab stop. A clickable chip is a button or a link, and a closable chip adds a remove button after it. | Key | What it does | | --- | --- | | `Tab` | Moves to the chip, then to its remove button. | | `Enter` or `Space` | Activates a clickable chip, or removes the chip when its remove button has focus. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwChip Represents a chip component for displaying compact elements representing an input, attribute, or action. | Parameter | Type | Description | | --- | --- | --- | | `Label` | `string` | Gets or sets the text label to display in the chip. | | `ChildContent` | `RenderFragment?` | Gets or sets the custom content to display in the chip. | | `Color` | `Color` | Gets or sets the color theme of the chip. | | `Variant` | `ButtonVariant` | Gets or sets the chip variant. | | `Size` | `ChipSize` | Gets or sets the size of the chip. | | `Closable` | `bool` | Gets or sets whether the chip is closable (shows a close button). | | `CloseIcon` | `Icon` | Gets or sets the icon to use for the close button. | | `OnClose` | `EventCallback` | Gets or sets the callback that is invoked when the close button is clicked. | | `OnClick` | `EventCallback` | Gets or sets the callback that is invoked when the chip is clicked. | | `StartIcon` | `Icon?` | Gets or sets whether to display an icon at the start of the chip. | | `EndIcon` | `Icon?` | Gets or sets whether to display an icon at the end of the chip. | | `Href` | `string` | Gets or sets the URL that the chip links to. | | `Target` | `string` | Gets or sets the name of the target frame or window for the navigation request. | | `Rel` | `string?` | Gets or sets the relationship between the linked resource and the current document. | | `Disabled` | `bool` | Disables the chip if set to true. | | `Avatar` | `string?` | Gets or sets the avatar text/initials to display at the start of the chip. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwChipGroup Represents a container component for grouping multiple `TwChip` components together. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the content to display within the chip group. | | `Legend` | `string?` | Gets or sets the legend text for the chip group. | | `LegendClass` | `string?` | Gets or sets the CSS class for the legend element. | | `Alignment` | `string` | Gets or sets the alignment of chips within the chip group. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwChipTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwChipTheme` by hand. --- # Class Merge > How twblazor merges conflicting Tailwind classes so the last one wins, and how to turn it off or add your own utilities with TwBlazorOptions.ClassMerge. Documentation page: https://twblazor.com/class-merge ## Overview Every twblazor component builds its `class` attribute from its theme classes, then your own `Class`. When two of those classes set the same CSS property, such as `px-4` from the theme and `px-2` from you, the one added last wins and the other is removed. Without merging, both would reach the element and the order of Tailwind's stylesheet, not your intent, would decide the result. It is built into twblazor, so there is nothing to install and nothing to set up. `ClassBuilder.Build()` does the merge for every component. The sections below show the rules it follows, and every result in them is produced by `ClassBuilder` when this page renders, so it is always what the library really does. The rules are those of the [tailwind-merge](https://github.com/dcastil/tailwind-merge) npm package for Tailwind CSS v4. Its class groups are generated into twblazor from that package, and twblazor's tests compare the two on several hundred class strings. See [Differences from tailwind-merge](https://twblazor.com/class-merge#class-merge-differences) for the two places they part. ```razor @* Renders px-2 and no px-6. The colors, height and the rest of the theme are untouched. *@ ``` ## Last conflicting class wins Two classes conflict when they set the same CSS property, such as two paddings, two font sizes or two display values. Of the classes that conflict, only the one written last is kept. It stays exactly where you wrote it, the earlier ones are removed, and every class that is not part of the conflict keeps its place. The classes do not need to be next to each other, and several conflicts are resolved in the same pass. ## Allows refinements A shorthand such as `p-3` sets several sides at once, and a class for one of those sides, such as `px-5`, is more specific. When the more specific class comes after the shorthand it refines it, so both are kept: padding everywhere, then a different horizontal padding. The order decides it. The other way round, the shorthand comes last and covers everything the specific class set, so the specific class is removed. ## Resolves non-trivial conflicts Classes with different names can still set the same property. The merge knows which Tailwind utilities overlap, including the cases that are easy to miss: - A shorthand and the classes it covers: `p` with `px`, `py` and each side, and the same for margin, inset, gap, overflow, border width, border color, rounded corners and scroll margin and padding. - `size-8` sets both width and height, so it replaces an earlier `w-4` and `h-6`. - `flex-1` sets grow, shrink and basis, so it replaces earlier `grow`, `shrink` and `basis-4`. - `line-clamp-1` sets display and overflow, so it replaces earlier classes for those. - Every display value conflicts with every other, as do the position values (`static`, `relative`, `absolute`) and the text decorations (`underline`, `line-through`). - A negative value conflicts with the positive class for the same property. ## Tells apart classes that share a prefix Many Tailwind prefixes are shared by unrelated properties. `text-` is used for font size, color, alignment and wrapping. `border-` is used for width, color and style. `bg-` is used for color, image, size, position and repeat. The value after the prefix decides which property a class sets, and only classes for the same property conflict. So `text-lg` replaces `text-sm` and leaves `text-red-500` alone, and a background color never removes a background size or position. ## Supports modifiers and stacked modifiers Classes only conflict when they have exactly the same modifiers, because each set of modifiers applies in a different situation. `hover:p-4` never removes `p-2`, and `md:p-4` never removes `lg:p-6`. This holds for every kind of modifier: state (`hover`, `focus`, `disabled`), responsive (`md`, `max-lg`), color scheme (`dark`), group and peer (`group-hover`, `peer-checked`), and data and aria attributes. When modifiers are stacked their order does not matter, so `hover:focus:` and `focus:hover:` are the same thing. Where the order does matter Some modifiers change which element is styled: `before`, `after`, `placeholder`, `file`, `marker`, `selection`, `first-line`, `first-letter`, `backdrop`, `details-content`, `*` and `**`, and any arbitrary variant. Moving another modifier from one side of these to the other changes the CSS Tailwind produces, so `before:hover:p-1` and `hover:before:p-2` are treated as different and both are kept. If you define such a variant yourself with `@custom-variant`, add its name to `OrderSensitiveVariants` so it is treated the same way. ## Supports a Tailwind prefix If your Tailwind build uses a prefix, Tailwind v4 writes it like a modifier at the start of the class, as in `tw:px-4` or `tw:hover:px-4`. Prefixed classes are merged with no configuration, and everything on this page applies to them: refinements, modifiers, arbitrary values and the important modifier. A prefixed class never conflicts with the unprefixed class of the same name. The two come from different stylesheets, so neither can stand in for the other. By default unprefixed classes are merged as well, which is right when the page mixes a prefixed and an unprefixed Tailwind build. If your whole application is prefixed, set `Prefix` to the value you gave `prefix(...)` in your stylesheet. Only classes that start with it are then treated as Tailwind utilities. Any other class, such as a `hidden` or `container` that belongs to another framework on the page, is left alone. ```csharp // app.css: @import "tailwindcss" prefix(tw); builder.Services.AddTwBlazor(options => options.ClassMerge.Prefix = "tw", Theme.CreateTheme); // "tw:px-4 tw:px-2" renders as "tw:px-2". // "hidden block" is left as it is: without the prefix they are not Tailwind classes. ``` The option only tells the merge what to treat as Tailwind. It does not add the prefix to anything: your copy of the theme must already be written with it, because Tailwind only generates the classes it finds in your source. ## Supports arbitrary values Arbitrary values take part in the merge like any other value. That covers both the square bracket form, `m-[10px]`, and the Tailwind v4 shorthand for a CSS variable, `w-(--sidebar)`. An arbitrary value conflicts with the named values for the same property, in either order. Labels are necessary in ambiguous cases A class like `text-[calc(var(--rebecca)-1rem)]` could be a font size or a text color, so the value is inspected for clues such as `calc()` or a number followed by a unit like `1rem`. When the type can't be told from the value, as in `text-[theme(myCustomScale.rebecca)]`, it is treated as a color. Add a CSS data type label, as Tailwind itself does, to say which one you mean: `text-[length:theme(myCustomScale.rebecca)]`. A variable in the shorthand form can never be inspected, so `text-(--my-size)` is always read as a color. Label it when it is something else: `text-(length:--my-size)`. The labels are `length`, `size`, `position`, `percentage`, `image`, `url`, `number`, `weight`, `family-name` and `shadow`. ## Supports arbitrary properties An arbitrary property, such as `[mask-type:alpha]`, conflicts with another arbitrary property that has the same property name. CSS variables set this way work the same, so a later `[--scroll-offset:44px]` replaces an earlier one. Modifiers apply as they do everywhere else: the two only conflict when their modifiers match. Conflicts between an arbitrary property and the Tailwind class for the same property are not resolved. Don't write `[padding:1rem] p-8` and expect one of them to go. ## Supports arbitrary variants Arbitrary variants, such as `[&>*]:` or `[&:nth-child(3)]:`, are modifiers like any other: two classes conflict when they have the same one. The selector is compared as written, so `[&>*]:` and `[&>p]:` are different. Like arbitrary properties, an arbitrary variant is never matched against a predefined modifier, so `[&:focus]:ring` and `focus:ring-4` are both kept. And because an arbitrary variant can change which element is styled, the order of the modifiers around it is kept too. ## Supports important modifier An important class only conflicts with other important classes, and an ordinary class only with ordinary ones. An important class already beats the ordinary one in the browser, so removing either would change nothing or lose a fallback. The modifier can be written after the class, `p-4!`, which is the Tailwind v4 form, or before it, `!p-4`, which is the older form Tailwind still accepts. The two forms conflict with each other, and both work with modifiers. ## Supports postfix modifiers A postfix modifier is the part after a slash. In `text-lg/7` it sets the line height as well as the font size, so the class also replaces an earlier `leading-6`. A `leading` class written after it refines it and is kept. Elsewhere the modifier is an opacity, as in `bg-red-500/50`, and does not change what the class conflicts with. A slash that is part of the value, as in the fraction `w-1/2`, is not a modifier at all. ## Preserves non-Tailwind classes A class that is not a Tailwind utility is never removed and keeps its place, so your own classes, component classes from other libraries and icon classes are safe. Such classes are not compared with each other either: writing one twice leaves it twice. A class counts as a Tailwind utility only when its value is one Tailwind has. `w-half` starts like a width, but `half` is not a width Tailwind knows, so it is left alone and does not remove `w-1/2`. ## Supports custom colors out of the box Where a utility takes a color, any name it has never seen is treated as a color. Colors from your own Tailwind theme therefore merge with no configuration, for text, background, border, ring, outline, shadow, fill, stroke and the rest. Custom font families work the same way. Custom sizes need a group The same rule means a custom name that is not a color is misread. With `--text-huge` in your theme, `text-huge` is taken for a color and will not replace `text-sm`, and a custom radius such as `rounded-brand` is not recognised at all. Sizes named like Tailwind's own, such as `text-3.5xl`, are fine. For any other name, add the class to the built-in group it belongs to, as shown under [Add your own utilities](https://twblazor.com/class-merge#class-merge-custom-names). ## Composition `ClassBuilder` merges once, when you call `Build()`, so you can add classes in as many calls as you like. The order of the calls is the order of the classes, which is why a component adds its theme classes first and your `Class` last. A conditional class takes part in the merge only when its condition is true. Whitespace is tidied on the way: extra spaces, tabs and line breaks become single spaces, and a null or empty string adds nothing. ```csharp var classes = new ClassBuilder("some-class") .AddClass("another-class yet-another-class") .AddClass("so-many-classes") .Build(); // → "some-class another-class yet-another-class so-many-classes" var compact = true; var button = new ClassBuilder("px-6 py-2") .AddClass("px-2", compact) .Build(); // → "py-2 px-2" ``` ## Configuration Merging needs no configuration. Leave `ClassMerge` alone and everything above applies. To change it, set it on the options you pass to `AddTwBlazor`. It is part of `TwBlazorOptions`, not the theme, and applies to your whole application. The configuration is read once, when `AddTwBlazor` runs, so set it there and not later. These are the settings: - `Enabled` turns merging on or off. It is on by default. - `Prefix` is the prefix of your Tailwind build, such as `tw`. Classes without it are then left alone. - `Groups` holds your own class groups, for utilities the merge does not know. - `OrderSensitiveVariants` names custom variants whose position among the other variants matters. - `CacheSize` is how many results are remembered. It is 2,048 by default, and 0 turns the cache off. ```csharp builder.Services.AddTwBlazor(options => { options.ClassMerge.Enabled = true; // the default options.ClassMerge.Prefix = "tw"; // only for a prefixed Tailwind build options.ClassMerge.CacheSize = 4096; // 2,048 by default options.ClassMerge.Groups.Add(new TwClassGroup("btn-size", ["btn"])); options.ClassMerge.OrderSensitiveVariants.Add("scrollbar"); }, Theme.CreateTheme); ``` ## Turn it off With `Enabled` set to `false` every class is rendered exactly as written, with only the surrounding whitespace trimmed. Both the theme's class and yours then reach the element, and which one applies is decided by their order in Tailwind's stylesheet. Turn it off only if you resolve conflicts some other way. ```csharp builder.Services.AddTwBlazor(options => options.ClassMerge.Enabled = false, Theme.CreateTheme); ``` ## Add your own utilities A `TwClassGroup` is a set of classes that conflict with each other. A class belongs to the group when it equals one of its prefixes or starts with the prefix and a dash, so the prefix `btn` matches `btn`, `btn-sm` and `btn-lg`, and does not match `btns`. Use it for classes you define with `@utility` or in your own CSS. Custom groups are checked before the built-in ones. Classes in a custom group get the same treatment as Tailwind's: modifiers, the important modifier, a leading minus and a postfix modifier are all understood, so `hover:btn-sm` only conflicts with `hover:btn-lg`. ```csharp // Of btn, btn-sm and btn-lg only the last one added is kept. options.ClassMerge.Groups.Add(new TwClassGroup("btn-size", ["btn"])); // "btn-sm btn-lg flex" renders as "btn-lg flex". ``` Give a group the name of a built-in one to add your classes to it. This is how to teach the merge a custom size from your Tailwind theme: the class then conflicts with everything else in that group and inherits what the group overrides. ```csharp // text-huge comes from --text-huge in your Tailwind theme. In the font-size group it // replaces text-sm, and an earlier leading-6, the way a built-in font size does. options.ClassMerge.Groups.Add(new TwClassGroup("font-size", []) { Classes = ["text-huge"] }); // rounded-brand comes from --radius-brand. options.ClassMerge.Groups.Add(new TwClassGroup("rounded", []) { Classes = ["rounded-brand"] }); // "text-sm leading-6 text-huge" renders as "text-huge". // "rounded-md rounded-brand" renders as "rounded-brand". ``` `Classes` matches a class by its whole name, where a prefix would also match everything that starts with it. Use it for a single class such as `text-huge`, so that an unrelated `text-huge-wide` is not pulled into the group. A group can have prefixes, classes or both. ## Override other groups Set `Overrides` to the names of groups that a later class from this one also removes. It works in one direction, like Tailwind's own shorthands: a later `pad-4` removes an earlier `px-2`, and a later `px-2` refines an earlier `pad-4`, so both are kept. Reusing the name of a built-in group, such as `p`, adds your classes to that group and keeps its existing overrides. The built-in groups are named as in tailwind-merge. The common ones are `p`, `px`, `py`, `m`, `w`, `h`, `size`, `display`, `font-size`, `font-weight`, `font-family`, `leading`, `text-color`, `bg-color`, `border-w`, `border-color`, `rounded`, `shadow` and `shadow-color`. ```csharp // A later pad-4 also removes earlier px and py classes. options.ClassMerge.Groups.Add(new TwClassGroup("spacing-all", ["pad"]) { Overrides = ["px", "py"], }); // Add gutter-* to the built-in padding group instead. options.ClassMerge.Groups.Add(new TwClassGroup("p", ["gutter"])); ``` `ModifierOverrides` does the same, but only for a class written with a postfix modifier. This is how the built-in font sizes work: `text-lg/7` removes an earlier line height and `text-lg` does not. Use it when the part after the slash in your own utility sets a second property. ```csharp // tile-2/50 sets an opacity as well, so it removes an earlier opacity-75. tile-2 does not. options.ClassMerge.Groups.Add(new TwClassGroup("tile", ["tile"]) { ModifierOverrides = ["opacity"], }); ``` ## What it does not do The merge only removes classes it is sure conflict. A few things are outside it: - It does not compare an arbitrary property with the utility for the same property, so `[padding:1rem] p-8` keeps both. - It does not remove duplicates of classes that are not Tailwind utilities. - It does not reorder classes. What is kept stays where it was written. - It does not know your own utilities or custom size names until you add a group for them. - It does not read your Tailwind configuration, so it cannot tell whether a class exists in your build. ## Differences from tailwind-merge twblazor gives the same result as tailwind-merge except in two cases, where it follows what Tailwind itself generates. - An unlabelled arbitrary background value made of position keywords, such as `bg-[right_0.5rem_center]`, is a background position, as it is to Tailwind. tailwind-merge reads it as a color unless you write `bg-[position:right_0.5rem_center]`. - A line height modifier is recognised after the older important syntax too, so `!text-sm/6` replaces an earlier `!leading-4` just as `text-sm/6!` does. Configuration differs too. tailwind-merge is extended with `extendTailwindMerge` and its own config format. twblazor has the settings listed under [Configuration](https://twblazor.com/class-merge#class-merge-configuration), set in C#. Its `Prefix` behaves like tailwind-merge's `prefix`, and `Groups`, `Overrides` and `ModifierOverrides` cover what `classGroups`, `conflictingClassGroups` and `conflictingClassGroupModifiers` do there. ## Performance Results are cached, so re-renders don't repeat the work. The cache is keyed on the full class string given to `Build()` and holds up to 2,048 different results before it starts again. Change that number with `CacheSize` if your application builds far more distinct class strings than that, or set it to 0 to always merge afresh. A component that renders with the same classes as last time gets its answer from one dictionary lookup. --- # TwCollapse > TwCollapse is a Blazor collapse component that expands and hides content. Bind IsOpen, set Title or HeaderContent, and react to OnToggle. Documentation page: https://twblazor.com/collapse ## Basic collapse The `TwCollapse` component provides a collapsible drawer panel that expands and collapses when the trigger button is clicked. ```razor

TwBlazor is a Tailwind CSS component library for Blazor that makes it easy to build modern, accessible UIs.

``` ## Default open Set `IsOpen="true"` to have the panel expanded on first render. ```razor

Install the TwBlazor NuGet package and call AddTwBlazor() in your service registration.

``` ## Two-way binding Use to control the panel state from a parent component. ```razor
Panel is @(isOpen ? "open" : "closed")

This panel is controlled from outside the component via two-way binding.

``` ## Custom header Use the `HeaderContent` parameter to replace the plain title with fully custom markup. ```razor Additional information

Custom header content lets you compose icons, badges, or any Blazor markup inside the trigger button.

``` ## Keyboard navigation The header is a button that reports whether its content is expanded. Collapsed content is hidden from the Tab order. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the header. | | `Enter` or `Space` | Expands or collapses the content. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwCollapse Represents a collapsible drawer component that shows or hides content when triggered. | Parameter | Type | Description | | --- | --- | --- | | `Title` | `string?` | Gets or sets the title text displayed in the collapse trigger button. | | `HeaderContent` | `RenderFragment?` | Gets or sets custom content to display inside the collapse trigger button. | | `ChildContent` | `RenderFragment?` | Gets or sets the content displayed inside the collapsible panel. | | `IsOpen` | `bool` | Gets or sets a value indicating whether the collapsible panel is open. | | `IsOpenChanged` | `EventCallback` | Gets or sets the callback invoked when `IsOpen` changes. | | `OnToggle` | `EventCallback` | Gets or sets the callback invoked when the collapse is toggled, providing the new open state. | | `HeadingLevel` | `int?` | Gets or sets the heading level (1 to 6) the trigger is wrapped in, so the collapse shows up in a screen reader's list of headings. Leave unset for a trigger with no heading. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwCollapseTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwCollapseTheme` by hand. --- # TwColorPicker > TwColorPicker is a Blazor colour picker component. Bind Value, choose an OutputFormat, and toggle ShowAlpha and ShowModeSwitch. Supports input variants. Documentation page: https://twblazor.com/color-picker ## Basic color picker Bind `Value` to let users pick a color from a labeled color picker input. ```razor ``` ```csharp private string selectedColor { get; set; } = "#3b82f6"; ``` ## With mode switch Set `ShowModeSwitch` to let users toggle between color input modes (e.g. hex and RGB). ```razor ``` ```csharp private string primaryColor { get; set; } = "#10b981"; ``` ## With alpha channel Set `ShowAlpha` to add an alpha channel slider for transparency. ```razor ``` ```csharp private string overlayColor { get; set; } = "#f59e0bff"; ``` ## Input variants Use the `Variant` property to switch between default, outlined and filled input styles. ```razor
``` ```csharp private string themeColor { get; set; } = "#8b5cf6"; private string accentColor { get; set; } = "#ec4899"; ``` ## Dense color picker Set `Dense` for a more compact input with a smaller height and text size. Every single-line input shares the same dense height, so they line up when used side by side. ```razor ``` ## Disabled state Use the `Disabled` property to prevent interaction with the color picker. ```razor ``` ## Output format Use `OutputFormat` to control whether the bound value is emitted as hex or RGB, regardless of the input format. ```razor
@* Output as Hex (default) *@

Value: @hexColor

@* Output as RGB with alpha *@

Value: @rgbColor

@* Input format is auto-detected, independent of output format *@

Value: @hslToRgbColor

``` ```csharp private string hexColor { get; set; } = "#3b82f6"; private string rgbColor { get; set; } = "rgba(16, 185, 129, 0.8)"; private string hslToRgbColor { get; set; } = "hsl(262, 83%, 58%)"; ``` ## Keyboard navigation The swatch opens the picker panel and the text field accepts a typed color. Inside the panel each slider is its own Tab stop. | Key | What it does | | --- | --- | | `Enter` or `Space` | On the swatch: opens the panel and moves focus into it. | | `Tab` or `Shift + Tab` | Moves between the controls in the open panel. Focus stays in the panel until it is closed. | | `Arrow Left` or `Arrow Right` | Saturation and lightness square: changes saturation. | | `Arrow Up` or `Arrow Down` | Saturation and lightness square: changes lightness. | | `Arrow Left` or `Arrow Right` | Hue and alpha sliders: decreases or increases the value. | | `Home` or `End` | Sets the focused slider to its minimum or maximum. | | `Enter` or `Space` | Presses the focused button: the eyedropper, the color format button, Cancel, or Confirm. | | `Escape` | Closes the panel without applying the color and returns focus to the swatch. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwColorPicker A color picker component that supports multiple color formats (Hex, RGB, HSL) with optional alpha channel. Provides both a visual color picker dialog and text input for manual color entry. | Parameter | Type | Description | | --- | --- | --- | | `Value` | `string` | Gets or sets the current color value. Supports Hex, RGB, and HSL formats. Default is "#000000" (black). | | `ValueChanged` | `EventCallback` | Gets or sets the event callback that is invoked when the color value changes. | | `OnFocus` | `EventCallback` | Gets or sets the event callback that is invoked when the input receives focus. | | `BindEvent` | `string` | Gets or sets the event name for binding. Default is "onchange". | | `ShowAlpha` | `bool` | Gets or sets whether to show and allow editing of the alpha (transparency) channel. Default is false. | | `ShowModeSwitch` | `bool` | Gets or sets whether to show the mode switch button to toggle between color formats. Default is false. | | `OutputFormat` | `ColorMode` | Gets or sets the output format for the color value (Hex, RGB, or HSL). Default is `Hex`. | | `PreferNativePicker` | `bool?` | Overrides automatic device detection for whether the browser's native picker should be used instead of the custom popover. Leave unset (`null`) to auto-detect based on the client platform (iOS and Android use the native picker by default). | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwColorPickerTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwColorPickerTheme` by hand. --- # TwDataTable > TwDataTable is a Blazor data table component with pagination, search, sortable columns and custom row classes for displaying structured data. Documentation page: https://twblazor.com/data-table ## Basic data table with pagination A feature-rich data table with pagination and search functionality. ```razor Product Category Price Stock @product.Name @product.Category £@product.Price.ToString("N2") @product.Stock ``` ```csharp public class Product { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Category { get; set; } = string.Empty; public decimal Price { get; set; } public int Stock { get; set; } } ``` ## Searchable data table Data table with search functionality to filter results. ```razor Product Category Price Stock @product.Name @product.Category £@product.Price.ToString("N2") @product.Stock

No products found matching your search.

``` ```csharp public class Product { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Category { get; set; } = string.Empty; public decimal Price { get; set; } public int Stock { get; set; } } ``` ## Data table without pagination Display all data without pagination controls. ```razor Name Department Role @user.Name @user.Department @user.Role ``` ```csharp public class User { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Department { get; set; } = string.Empty; public string Role { get; set; } = string.Empty; } ``` ## Custom row classes Data table with custom row styling based on conditions. ```razor Product Category Price Stock @{ var rowClass = product.Stock < 10 ? "bg-red-50 dark:bg-red-900/20" : ""; } @product.Name @product.Category £@product.Price.ToString("N2") @if (product.Stock < 10) { @product.Stock (Low Stock) } else { @product.Stock } ``` ```csharp public class Product { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Category { get; set; } = string.Empty; public decimal Price { get; set; } public int Stock { get; set; } } ``` ## Sortable data table with columns Data table with per-column sortability. Click column headers to sort. Some columns are sortable (with icons), others are not. ```razor

No products found.

``` ```csharp // Define columns with per-column sortability private readonly List> _productColumns = new() { new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true, // Sortable with alpha icons (auto-detected) }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category, IsSortable = false, // Sortable disabled. }, new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, IsSortable = true, // Sortable with numeric icons (auto-detected from decimal type) CellFormatter = p => $"£{p.Price:N2}" }, new TwDataTableColumn { Name = "stock", Title = "Stock", PropertySelector = p => p.Stock, CellFormatter = p => p.Stock < 10 ? $"{p.Stock} (Low Stock)" : p.Stock.ToString(), IsSortable = true } }; ``` ## Column widths and fixed layout Give a column a `Width` to size it. Any CSS length works, such as `40%` or `8rem`, and columns without a width share the rest. Add `FixedLayout` so the columns keep their widths as you page, sort and search, instead of jumping to fit each page's content. With `TableHeader` and `TableRow`, pass a `ColumnGroup` of `TwTableColumn` elements instead, as on `TwTable`. ```razor ``` ```csharp private readonly List> _sizedColumns = new() { new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category, Width = "25%" }, new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, IsSortable = true, Width = "8rem", CellFormatter = p => $"£{p.Price:N2}" } }; ``` ## Column menu Set `ColumnMenu` and each column header gains an options button that opens a [TwMenu](https://twblazor.com/menu.md). It sorts the column, groups by it when it is `Groupable`, moves it left or right, and hides it. Its Columns group ticks any column on or off, so a hidden column can be shown again, and Reset columns puts everything back. Set `Hideable = false` on a column that identifies each row so it cannot be hidden, and `Visible = false` on a column that should start hidden. Every change is announced to screen readers. ```razor ``` ```csharp private readonly List> _panelColumns = new() { // The name identifies each row, so it always stays visible. new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true, Hideable = false }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category }, new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, IsSortable = true, CellFormatter = p => $"£{p.Price:N2}" }, // Starts hidden; people can show it from the panel. new TwDataTableColumn { Name = "stock", Title = "Stock", PropertySelector = p => p.Stock, IsSortable = true, Visible = false } }; ``` ## Filtering columns Set `Filterable` on a column and its header gains a filter button. It opens a filter with up to two conditions, joined with And or Or, then Filter applies them and Clear removes them. The conditions and the value field suit the column's values: text conditions such as Contains and Starts with, comparisons such as Is greater than for numbers and dates, and a list for true or false values and enums. Set `FilterType` when the type cannot be worked out, such as before an `ItemsProvider` has loaded any rows, and `FilterOperators` to choose the conditions on offer. Filters are saved with the table's state, sent to an `ItemsProvider` in `Filters`, and announced with the number of rows they leave. ```razor ``` ```csharp private readonly List> _filterColumns = new() { new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true, Filterable = true }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category, Filterable = true }, // Numbers get comparisons such as "is greater than", and the value is a number field. new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, IsSortable = true, Filterable = true, CellFormatter = p => $"£{p.Price:N2}" }, new TwDataTableColumn { Name = "stock", Title = "Stock", PropertySelector = p => p.Stock, IsSortable = true, Filterable = true } }; ``` ## Resizable columns Set `ResizableColumns` and every column's border becomes a resize handle, from [TwTable](https://twblazor.com/table#resizable-columns). Drag it, or focus it with `Tab` and press `Arrow Left` or `Arrow Right`, holding `Shift` for bigger steps. Screen readers hear each border as "Resize Price" with the column's width. The widths are saved with the table's state. `Resizable = false` keeps a column at its width. ```razor ``` ## Grouping rows Set `Groupable` on the columns people can group by, and a Group by list appears above the table. `GroupBy` picks the grouping the table starts with. Each group sits under a header row with a button that expands or collapses it, and Expand all groups and Collapse all groups work on every group at once. Rows keep the table's sort inside each group. A page that starts part way through a group repeats its header. Use `GroupHeaderTemplate` to add a summary to each header, such as a total. ```razor Stock value £@group.Items.Sum(p => p.Price * p.Stock).ToString("N0") ``` ```csharp private readonly List> _groupColumns = new() { new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category, IsSortable = true, Groupable = true }, new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, IsSortable = true, CellFormatter = p => $"£{p.Price:N2}" }, // Groups by the stock level's label rather than every distinct number. new TwDataTableColumn { Name = "level", Title = "Stock level", PropertySelector = p => p.Stock < 10 ? "Low" : "In stock", Groupable = true } }; ``` ## Virtualizing thousands of rows Set `EnableVirtualization` and the table renders only the rows scrolled into view, so it stays fast with tens of thousands of rows. The rows scroll inside the table instead of being paged, and the header stays in view. Change the height with `Height`. Keep each row to one line, about `ItemSize` pixels tall. Screen readers are told the full row count and each row's place, so they still read "row 5000 of 10000". Sorting, searching, filtering, the column menu and grouping all work as before. ```razor ``` ```csharp private readonly List orders = [.. Enumerable.Range(1, 10_000).Select(i => new Order( i, $"Customer {(i * 37) % 900 + 1}", new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Local).AddHours(i * 7), Math.Round(5 + (i * 7919 % 50_000) / 100m, 2)))]; private readonly List> _orderColumns = new() { new TwDataTableColumn { Name = "number", Title = "Order", PropertySelector = o => o.Number, IsSortable = true }, new TwDataTableColumn { Name = "customer", Title = "Customer", PropertySelector = o => o.Customer, IsSortable = true }, new TwDataTableColumn { Name = "placed", Title = "Placed", PropertySelector = o => o.Placed, IsSortable = true, CellFormatter = o => o.Placed.ToString("dd/MM/yyyy HH:mm") }, new TwDataTableColumn { Name = "total", Title = "Total", PropertySelector = o => o.Total, IsSortable = true, CellFormatter = o => $"£{o.Total:N2}" } }; public record Order(int Number, string Customer, DateTime Placed, decimal Total); ``` ## Loading rows from a server For data that is too big to load at once, give the table an `ItemsProvider` in place of `Items`. The table asks it for one page at a time, passing the sort, search and column filters, so your database or API does the work and returns just those rows with the total count. Combine it with `EnableVirtualization` to load rows as they scroll into view. While rows load the table is marked busy, and the search result count is announced once they arrive. Call `RefreshDataAsync` after the data changes elsewhere. ```razor ``` ```csharp // Stands in for a database query: in a real app, pass the request on to your API or Entity Framework. private async ValueTask> LoadOrdersAsync(TwDataTableItemsRequest request) { await Task.Delay(300, request.CancellationToken); IEnumerable query = orders; if (!string.IsNullOrWhiteSpace(request.SearchQuery)) { query = query.Where(o => o.Customer.Contains(request.SearchQuery, StringComparison.OrdinalIgnoreCase)); } query = (request.SortColumn, request.SortDirection) switch { ("number", SortDirection.Descending) => query.OrderByDescending(o => o.Number), ("customer", SortDirection.Ascending) => query.OrderBy(o => o.Customer), ("customer", SortDirection.Descending) => query.OrderByDescending(o => o.Customer), ("placed", SortDirection.Ascending) => query.OrderBy(o => o.Placed), ("placed", SortDirection.Descending) => query.OrderByDescending(o => o.Placed), ("total", SortDirection.Ascending) => query.OrderBy(o => o.Total), ("total", SortDirection.Descending) => query.OrderByDescending(o => o.Total), _ => query }; var matching = query.ToList(); var page = matching.Skip(request.StartIndex).Take(request.Count ?? matching.Count).ToList(); return new TwDataTableItemsResult(page, matching.Count); } ``` ## Editing rows Set `Editable` to add an Actions column with an Edit button on each row. Editing turns the row's `Editable` columns into editors that match their values: a text field, a number field, a checkbox, a date picker or a list for an enum. Give a column an `EditTemplate` for any other editor. Save runs each column's `Validator`, marks any field that needs fixing and moves focus to it. Once every value is fine, each `ValueSetter` writes its value to the row and `RowSaved` is raised with the old and new values, ready to send to your API. Escape or Cancel leaves the row as it was, and focus goes back to the row's Edit button. ```razor

@lastSaved

``` ```csharp private readonly List editableProducts = [ new Product { Id = 1, Name = "Kettle", Category = "Kitchen", Price = 30, Stock = 14 }, new Product { Id = 2, Name = "Armchair", Category = "Furniture", Price = 250, Stock = 3 }, new Product { Id = 3, Name = "Desk lamp", Category = "Lighting", Price = 45, Stock = 22 }, new Product { Id = 4, Name = "Blender", Category = "Kitchen", Price = 60, Stock = 8 } ]; private readonly List> _editableColumns = new() { new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true, Editable = true, ValueSetter = (p, value) => p.Name = (string?)value ?? string.Empty, Validator = (_, value) => string.IsNullOrWhiteSpace(value as string) ? "Enter a product name" : null }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category }, new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, Editable = true, ValueSetter = (p, value) => p.Price = (decimal)value!, Validator = (_, value) => value is decimal price && price <= 0 ? "Enter a price above £0" : null }, new TwDataTableColumn { Name = "stock", Title = "Stock", PropertySelector = p => p.Stock, Editable = true, ValueSetter = (p, value) => p.Stock = (int)value! } }; private string lastSaved = string.Empty; private Task OnProductSaved(TwDataTableRowEdit edit) { // Send the change to your API here; OriginalValues can put the row back if that fails. var changed = string.Join(", ", edit.ChangedColumns); lastSaved = changed.Length == 0 ? $"{edit.Item.Name} saved with no changes." : $"{edit.Item.Name} saved: {changed} changed."; return Task.CompletedTask; } ``` ## Exporting to CSV and Excel Set `Exportable` to add Export CSV and Export Excel buttons. An export holds the columns on screen in their current order, and by default every row that matches the search in its current sort, across all pages. Change that with `ExportScope`, or pick the buttons with `ExportFormats`. The Excel file keeps numbers, dates and true or false values as their own types, so they can be summed and filtered. Give a column an `ExportFormatter` to write a different value from the one on screen, or set `Exportable = false` to leave it out. Text that a spreadsheet would run as a formula is escaped. ```razor ``` ```csharp private readonly List> _exportColumns = new() { new TwDataTableColumn { Name = "name", Title = "Product Name", PropertySelector = p => p.Name, IsSortable = true }, new TwDataTableColumn { Name = "category", Title = "Category", PropertySelector = p => p.Category }, // On screen the price reads "£2,999.00"; the export keeps the number so a spreadsheet can total it. new TwDataTableColumn { Name = "price", Title = "Price", PropertySelector = p => p.Price, IsSortable = true, CellFormatter = p => $"£{p.Price:N2}" }, new TwDataTableColumn { Name = "stock", Title = "Stock", PropertySelector = p => p.Stock, ExportFormatter = p => p.Stock < 10 ? "Low" : "In stock" } }; ``` To build the file yourself, call `GetCsv` or `GetExcel` on the table, or use `TwDataTableExport` with any rows and columns, for example to send a report from the server. ```csharp byte[] workbook = TwDataTableExport.ToExcel(orders, columns, sheetName: "Orders"); string csv = TwDataTableExport.ToCsv(orders, columns); ``` ## Saving the table's state Give the table a `StateStorageKey` and it remembers its sort, search, page, page size and columns in the browser, so it comes back the way the person left it. Sort or hide a column below, then reload the page. `ResetStateAsync` puts it back to how the parameters define it. ```razor ``` ```csharp private TwDataTable? storedTable; private async Task ResetStoredTableAsync() { if (storedTable is not null) { await storedTable.ResetStateAsync(); } } ``` ## Managing the state yourself To keep the state somewhere else, such as a user's profile or the page address, bind `@bind-State`. The table raises a new `TwDataTableState` after every change, and restores whichever state you pass in. It is made of plain values, so it serializes to JSON as it is. Columns are matched by `Name`, so a saved state survives columns being added or removed. ```razor

The current state:

``` ```csharp private TwDataTableState? tableState; private string tableStateJson => tableState is null ? "Sort, search or change page to see the state." : System.Text.Json.JsonSerializer.Serialize(tableState, new System.Text.Json.JsonSerializerOptions(System.Text.Json.JsonSerializerDefaults.Web) { WriteIndented = true }); ``` ## Keyboard navigation The table is read as a native table. Its controls are ordinary buttons, menus and fields, and sort, search, filter, page, grouping and column changes are announced. With ResizableColumns, each column's border is a separator that reports the column's width. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves through the toolbar, each column's sort, filter and options buttons, the resize separators, the table's scroll area and the pagination. | | `Enter` or `Space` | On a sort button: sorts by that column, then reverses the order, then clears it. | | `Arrow Left` or `Arrow Right` or `Arrow Up` or `Arrow Down` or `Pg.Up` or `Pg.Down` | In the table's scroll area: scrolls a table that is wider or taller than its container. A virtualized table renders the rows as they scroll into view. | | `Enter` | Commits the search text. | | `Enter` or `Space` or `Arrow Down` or `Arrow Up` | On a column's options button: opens its menu, on the first or last item. | | `Arrow Up` or `Arrow Down` or `Enter` or `Space` or `Escape` | In a column's menu: moves between its items, chooses one, or closes it. A column toggle flips and the menu stays open. | | `Enter` or `Space` | On a column's filter button: opens its filter with focus on the first condition. | | `Tab` or `Enter` or `Escape` | In a filter: moves between its fields and buttons, applies the filter, or closes it without changing it. Focus returns to the filter button. | | `Arrow Left` or `Arrow Right` | On a resize separator: makes the column wider or narrower, in bigger steps with Shift. The key moves the border the way it points, in either text direction. | | `Enter` or `Space` | On an export button: downloads the table, then announces how many rows it holds. | | `Enter` or `Space` | On a group header's button: expands or collapses that group. The button says whether the group is expanded. | | `Enter` or `Space` or `Arrow Down` | On the Group by list: opens it to choose a column to group by, or No grouping. | | `Enter` or `Space` | On a row's Edit button: turns the row into editors and moves focus to the first one. | | `Tab` or `Shift + Tab` | While a row is edited: moves between its editors and the Save and Cancel buttons. | | `Escape` | While a row is edited: cancels the edit and returns focus to the row's Edit button. A picker or list open in the row closes first. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDataTable Represents a generic data table component for displaying and managing a collection of items with features such as search, pagination, and customizable rendering. | Parameter | Type | Description | | --- | --- | --- | | `ColumnMenu` | `bool` | Whether each column header has an options button that opens a `TwMenu` for sorting, grouping, moving and hiding the column, showing any hidden column again, and resetting the columns. Only applies when `Columns` is used. Defaults to `false`. | | `ResizableColumns` | `bool` | Whether people can resize the columns by dragging the border at the end of a column's header, or by focusing that border and pressing the arrow keys (`ResizableColumns`). Only applies when `Columns` is used. Defaults to `false`. | | `Editable` | `bool` | Whether rows can be edited in place. Adds an Actions column with an Edit button on each row, which turns the row's `Editable` cells into editors with Save and Cancel buttons. Only applies when `Columns` is used. Defaults to `false`. | | `CanEditRow` | `Func?` | Gets or sets which rows can be edited, or `null` for every row. Rows it returns `false` for get no Edit button. | | `RowSaved` | `EventCallback>` | Raised after a person saves an edited row. Every column with a `ValueSetter` has already written its value to the row, so this is the place to save the row to a database or API. | | `RowEditCancelled` | `EventCallback` | Raised when a person cancels editing a row. The row is left as it was. | | `RowLabel` | `Func?` | Gets or sets how a row is named in the Edit, Save and Cancel buttons' accessible names, such as "Edit Kettle". Defaults to the text of the first visible column. | | `Exportable` | `bool` | Whether to show buttons that download the table as a file. Only applies when `Columns` is used. Defaults to `false`. | | `ExportFormats` | `TwDataTableExportFormats` | Gets or sets which file formats get an export button. Defaults to `All`. | | `ExportScope` | `TwDataTableExportScope` | Gets or sets which rows the export buttons include. Defaults to `Filtered`: every row that matches the search, in the order it is sorted. | | `ExportFileName` | `string` | Gets or sets the name of the downloaded file, without its extension. It also names the Excel worksheet. Defaults to `export`. | | `GroupBy` | `string?` | Gets or sets the `Name` of the column to group the rows by when the table first renders. The column needs `Groupable` set. People can change the grouping from the Group by list, which appears once any column is groupable. | | `GroupHeaderTemplate` | `RenderFragment>?` | Gets or sets extra content for each group header, shown after the group's name and row count, such as a total. The context is the `TwDataTableGroup`. | | `GroupByLabel` | `string?` | Gets or sets the label of the Group by list. Defaults to the localized `DataTable_GroupBy` text ("Group by"). | | `State` | `TwDataTableState?` | Gets or sets the table's state: its sort, search, page, page size and columns. Bind it with `@bind-State` to keep a copy that follows every change, then save that copy wherever suits you and pass it back later to restore the table. When it is `null` the table starts from its parameters. | | `StateChanged` | `EventCallback` | Raised with a new `TwDataTableState` each time a person sorts, searches, changes page or page size, or changes the columns. | | `StateStorageKey` | `string?` | Gets or sets a key to save the table's state under in the browser's local storage. The table then comes back the way the person left it on their next visit. Use a key that is unique to the table, such as `"orders-table"`. Ignored while `State` is set, so state you manage yourself always wins. | | `EnableVirtualization` | `bool` | Whether to render only the rows scrolled into view, so a table of thousands of rows stays fast (`EnableVirtualization`). The rows scroll inside the table, which is `Height` tall, and the pagination is replaced by scrolling. Defaults to `false`. | | `ItemSize` | `float` | Gets or sets the height of a row in pixels when `EnableVirtualization` is set, used to work out which rows are in view before they render. Defaults to `41`, the height of a row in the default theme. | | `OverscanCount` | `int` | Gets or sets how many extra rows to render above and below the ones in view when `EnableVirtualization` is set, so fast scrolling does not show gaps. Defaults to `5`. | | `Height` | `string?` | Gets or sets the tallest the table can grow before its rows scroll inside it, as any CSS length. Defaults to `32rem` when `EnableVirtualization` is set, and to no limit otherwise. | | `StickyHeader` | `bool` | Whether the header row stays in view while the rows scroll. Always on when `EnableVirtualization` is set. Defaults to `false`. | | `ItemsProvider` | `TwDataTableItemsProvider?` | Gets or sets a function that loads rows on demand, such as from a database or an API, in place of `Items`. The table passes it the page, sort, search and column filters, so the work happens where the data lives. Grouping is not available, and an export of every row asks the function for all of them. | | `LoadingContent` | `RenderFragment?` | Gets or sets what to show while `ItemsProvider` loads the first rows. Defaults to the localized `DataTable_Loading` text ("Loading…"). | | `Searchable` | `bool` | Whether the table has search functionality. | | `SearchLabel` | `string?` | Label for the search field. Defaults to the localized `DataTable_SearchLabel` text ("Search"). | | `SearchPlaceholder` | `string?` | Placeholder text for the search field. Defaults to the localized `DataTable_SearchPlaceholder` text ("Search…"). | | `Items` | `List` | The data items to display in the table. | | `ItemsChanged` | `EventCallback>` | Event callback when Items parameter changes. | | `TableHeader` | `RenderFragment?` | RenderFragment for table header cells. | | `TableRow` | `RenderFragment?` | RenderFragment for table row cells, receives the row item. | | `EmptyContent` | `RenderFragment?` | Content to display when there are no items. | | `RowClass` | `string?` | Additional CSS classes for table rows. | | `DefineTableRows` | `bool` | If true, manually define `` elements in TableRow. Otherwise, they are auto-generated. | | `EnablePagination` | `bool` | Whether the rows are split into pages, with a pagination below the table (`EnablePagination`). Defaults to `true`. Ignored while `EnableVirtualization` is set. | | `Pageable` | `bool` | Whether the rows are split into pages. Use `EnablePagination`, which this sets. | | `RowsPerPage` | `int` | Number of rows per page. | | `RowsPerPageChanged` | `EventCallback` | Event callback when RowsPerPage parameter changes. | | `RowsPerPageOptions` | `int[]` | Options for rows per page dropdown. | | `ComfortablePagination` | `bool` | Whether to render the pagination controls with more comfortable, regular-size buttons instead of the default dense (smaller, more compact) buttons. Defaults to `false`. Only applies when `EnablePagination` is `true`. | | `ColumnGroup` | `RenderFragment?` | Optional column definitions for a manually defined table (`TableHeader` and `TableRow`), passed to `ColumnGroup`. Use `TwTableColumn` to set column widths. When `Columns` is used, set `Width` on each column instead. | | `FixedLayout` | `bool` | Whether column widths come from the column definitions and header row instead of the cell content (`FixedLayout`). Columns then keep the same width as the rows change from page to page, or as a search filters them. Defaults to `false`. | | `Striped` | `bool` | Whether to show striped rows. | | `Hoverable` | `bool` | Whether to show hover effect on rows. | | `Bordered` | `bool` | Whether to show borders. | | `HeaderClass` | `string?` | Additional CSS classes for the table header. | | `HeaderRowClass` | `string?` | Additional CSS classes for the header row (tr element) when using Columns. Applied on top of the shared `Header` theme token, so customizing that theme property affects this header row too. | | `BodyClass` | `string?` | Additional CSS classes for the table body. | | `TableClass` | `string?` | Additional CSS classes for the table element itself. | | `TableAttributes` | `Dictionary` | Additional attributes for the table element. | | `Columns` | `List>?` | Defines the columns for the table. When provided, headers will be auto-generated with sorting support. Leave null to use manual TableHeader and TableRow fragments. | | `Caption` | `RenderFragment?` | Optional caption content for the table, forwarded to the underlying `TwTable`. Provides an accessible name/description for the table that is programmatically associated with it via ``. Visually hidden by default unless `CaptionVisible` is `true`. | | `CaptionVisible` | `bool` | Whether the `Caption` should be visible. Defaults to `false`, rendering the caption visually hidden (but still available to assistive technology). | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwTableTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwTableTheme` by hand. --- # TwDatePicker > TwDatePicker is a Blazor date picker component with a calendar popup. Bind Value, set MinDate, MaxDate, Format and Placeholder, or use the native input. Documentation page: https://twblazor.com/date-picker ## Basic date picker Bind `SelectedDate` for a `DateTime` value, or `Value` for a plain string. ```razor

@@bind-SelectedDate (DateTime): @SelectedDate.ToShortDateString()

@@bind-Value (string): @SelectedDateTextValue

``` ```csharp public DateTime SelectedDate { get; set; } = DateTime.Now; public string SelectedDateTextValue { get; set; } = DateTime.Now.ToShortDateString(); ``` ## Custom format `Format` accepts any .NET custom date format string and is used for both display and for parsing what's typed - the placeholder updates to match automatically. Use it for US-style month-first dates, dash-separated dates, or any other pattern your locale needs. ```razor
``` ```csharp public DateTime SelectedDate { get; set; } = DateTime.Now; public string SelectedDateTextValue { get; set; } = DateTime.Now.ToShortDateString(); ``` ## Input variants The DatePicker supports different visual variants for the input field. ```razor
``` ```csharp public DateTime SelectedDate { get; set; } = DateTime.Now; public string SelectedDateTextValue { get; set; } = DateTime.Now.ToShortDateString(); ``` ## Dense date picker Set `Dense` for a more compact input with a smaller height and text size. Every single-line input shares the same dense height, so they line up when used side by side. ```razor ``` ```csharp public DateTime SelectedDate { get; set; } = DateTime.Now; public string SelectedDateTextValue { get; set; } = DateTime.Now.ToShortDateString(); ``` ## Disabled and readonly date picker Use the `Disabled` and `ReadOnly` properties to restrict interaction with the date picker. ```razor
``` ```csharp public DateTime SelectedDate { get; set; } = DateTime.Now; public string SelectedDateTextValue { get; set; } = DateTime.Now.ToShortDateString(); ``` ## Keyboard navigation Type a date straight into the field, or open the calendar. The calendar does not open just because the field has focus. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the field. The panel stays closed, so you can tab straight past it. | | `Arrow Down` | Opens the panel and moves focus into it. | | `Enter` or `Space` | On the icon button beside the field: opens the panel and moves focus into it, or closes it. | | `Enter` | Commits a value typed into the field. | | `Escape` | Closes the panel and returns focus to the field. Works from the field and from inside the panel. | | `Tab` or `Shift + Tab` | Moves between the controls in the open panel. Focus stays in the panel until it is closed. | | `Arrow Left` or `Arrow Right` | Moves to the previous or next day. Moving past the start or end of the month turns the page. The two keys swap in a right to left layout. | | `Arrow Up` or `Arrow Down` | Moves to the same weekday in the previous or next week. | | `Home` or `End` | Moves to the first or last day of the week. | | `Pg.Up` or `Pg.Down` | Moves to the previous or next month. | | `Shift + Page Up` or `Shift + Page Down` | Moves to the previous or next year. | | `Enter` or `Space` | Selects the focused day. | | `Enter` or `Space` | On the month and year heading: switches to the list of months, then of years. Focus lands on the current one, and Tab moves between them. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDatePicker Represents a date picker component that allows users to select a date from a calendar interface or enter a date manually. | Parameter | Type | Description | | --- | --- | --- | | `Placeholder` | `string?` | The placeholder text to display when no date is selected. | | `SelectedDate` | `DateTime` | The `DateTime` value of the selected date. | | `SelectedDateChanged` | `EventCallback` | The `DateTime` bound value of the selected date. | | `Value` | `string?` | The `string` value displayed in the textbox to the user. | | `ValueChanged` | `EventCallback` | The `string` bound value displayed in the textbox to the user. | | `Format` | `string?` | The string format used to display the `SelectedDate`. Leave unset to fall back to `DefaultFormat` (default 'dd/MM/yyyy'). | | `NativeInputType` | `string` | The HTML input type to use when the native picker is active, default value is 'date'. Set to 'datetime-local' by `TwDateTimePicker` so it can reuse this component's native-picker support. | | `NativeFormat` | `string` | The string format used for `Value` when the native picker is active, default value is 'yyyy-MM-dd'. This must match the ISO format expected by `NativeInputType`. | | `NativeStep` | `string?` | The HTML `step` attribute applied to the input when the native picker is active, in the units `NativeInputType` expects (days for 'date', seconds for 'datetime-local'). Set by `TwDateTimePicker` from its `Step`. Leave unset for the browser default. | | `FocusedChildContent` | `RenderFragment?` | Child content to be rendered when the date picker is focused, this is used for `TwDateTimePicker`. | | `BodyClasses` | `string` | Gets or sets the CSS class names to apply to the body element of the component. | | `PreferNativePicker` | `bool?` | Overrides automatic device detection for whether the browser's native picker should be used instead of the custom popover. Leave unset (`null`) to auto-detect based on the client platform (iOS and Android use the native picker by default). | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwDatePickerTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwDatePickerTheme` by hand. --- # TwDateRangePicker > TwDateRangePicker is a Blazor date range picker with a two-month calendar popup. Bind Value or SelectedRange and constrain it with MinDate and MaxDate. Documentation page: https://twblazor.com/date-range-picker ## Basic date range picker Bind `SelectedRange` for a `KeyValuePair` value (`Key` = start, `Value` = end). Select a start date, then an end date - the range highlights across both calendar months and survives month navigation. Shares its theme (`TwDatePickerTheme`) with [TwDatePicker](https://twblazor.com/date-picker.md). ```razor

@@bind-SelectedRange: @(SelectedRange.Key?.ToShortDateString() ?? "-") - @(SelectedRange.Value?.ToShortDateString() ?? "-")

``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Custom format `Format` is a plain .NET custom date format string applied identically to both the start and end date - the same parameter [TwDatePicker](https://twblazor.com/date-picker.md) uses. The separator between the two dates defaults to `" - "` and is configurable via `RangeSeparator`. ```razor
``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Min and max date Use the `MinDate` and `MaxDate` properties to restrict the selectable range. Out-of-bounds days render disabled and the month navigation arrows stop at the boundary. ```razor ``` ```csharp public KeyValuePair BoundedRange { get; set; } public DateTime MinDate { get; set; } = DateTime.Today; public DateTime MaxDate { get; set; } = DateTime.Today.AddDays(30); ``` ## Input variants The date range picker supports the same visual variants as the other text inputs. ```razor
``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Dense date range picker Set `Dense` for a more compact input with a smaller height and text size. Every single-line input shares the same dense height, so they line up when used side by side. ```razor ``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Disabled and readonly date range picker Use the `Disabled` and `ReadOnly` properties to restrict interaction with the date range picker. ```razor
``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Keyboard navigation Type a range into the field, or open the calendar, which shows two months side by side. Pick the start day, then the end day. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the field. The panel stays closed, so you can tab straight past it. | | `Arrow Down` | Opens the panel and moves focus into it. | | `Enter` or `Space` | On the icon button beside the field: opens the panel and moves focus into it, or closes it. | | `Enter` | Commits a value typed into the field. | | `Escape` | Closes the panel and returns focus to the field. Works from the field and from inside the panel. | | `Tab` or `Shift + Tab` | Moves between the controls in the open panel. Focus stays in the panel until it is closed. | | `Arrow Left` or `Arrow Right` | Moves to the previous or next day. Moving past the start or end of the month turns the page. The two keys swap in a right to left layout. | | `Arrow Up` or `Arrow Down` | Moves to the same weekday in the previous or next week. | | `Home` or `End` | Moves to the first or last day of the week. | | `Pg.Up` or `Pg.Down` | Moves to the previous or next month. | | `Shift + Page Up` or `Shift + Page Down` | Moves to the previous or next year. | | `Enter` or `Space` | Selects the focused day. | | `Enter` or `Space` | On the month and year heading: switches to the list of months, then of years. Focus lands on the current one, and Tab moves between them. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDateRangePicker Represents a date range picker component that lets users select a start and end date from a calendar popover showing two months side by side (one on narrow/mobile screens), or by typing both dates directly. | Parameter | Type | Description | | --- | --- | --- | | `Placeholder` | `string?` | The placeholder text to display when no range is selected. | | `SelectedRange` | `KeyValuePair` | The selected date range: `Key` is the start date, `Value` is the end date. Either (or both) may be `null` - both null means no range has been started yet, and a non-null `Key` with a null `Value` means only the start has been picked so far. `Key` is always less than or equal to `Value` when both are set - this component swaps the two dates as needed so callers never need to sort them themselves. | | `SelectedRangeChanged` | `EventCallback>` | The bound `SelectedRange` value; invoked whenever it changes, including after only the range's start has been picked (`Value` still `null`) so callers can reflect an in-progress selection. | | `Value` | `string?` | The `string` value displayed in the textbox to the user. | | `ValueChanged` | `EventCallback` | The `string` bound value displayed in the textbox to the user. | | `Format` | `string?` | The .NET custom date format string used to display and parse each date in `SelectedRange`, applied identically to both the start and the end date. Any valid pattern works here, e.g. 'MM/dd/yyyy' for US-style dates or 'dd-MM-yyyy' for a dash-separated one. Leave unset to fall back to `DefaultFormat` (default 'dd/MM/yyyy'). | | `RangeSeparator` | `string?` | The separator inserted between the two dates in `Value`. A locale-neutral symbol (like the default, " - ") reads better than a word like "to" that would need translating for non-English users. The surrounding spaces also mean an everyday dash-containing `Format` like "dd-MM-yyyy" (no spaces around its own "-") doesn't collide with it when typed text is split back apart - only a Format that itself embeds " - " (spaces around a dash) would, so avoid that specific combination if you override either parameter. Leave unset to fall back to `DefaultRangeSeparator`. | | `MinDate` | `DateTime?` | The earliest selectable date (inclusive). Days before this are disabled in the calendar and rejected when typed; the Previous month button is also disabled once it's reached. | | `MaxDate` | `DateTime?` | The latest selectable date (inclusive). Days after this are disabled in the calendar and rejected when typed; the Next month button is also disabled once it's reached. | | `BodyClasses` | `string` | Gets or sets the CSS class names to apply to the body element of the component. | | `PreferNativePicker` | `bool?` | Overrides automatic device detection for whether the browser's native picker should be used instead of the custom popover. Leave unset (`null`) to auto-detect based on the client platform (iOS and Android use the native picker by default). | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwDatePickerTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwDatePickerTheme` by hand. --- # TwDateTimePicker > TwDateTimePicker is a Blazor component for choosing a date and time in one input. Bind Value, set Format and Placeholder, and use PreferNativePicker on mobile. Documentation page: https://twblazor.com/datetime-picker ## Basic DateTime picker Bind `SelectedDateTime` for a `DateTime` value, or `Value` for a plain string. ```razor

@@bind-SelectedDate (DateTime): @SelectedDateTime.ToShortDateString()

@@bind-Value (string): @SelectedDateTimeTextValue

``` ```csharp public DateTime SelectedDateTime { get; set; } = DateTime.Now; public string SelectedDateTimeTextValue { get; set; } = DateTime.Now.ToString("dd/MM/yyyy HH:mm"); ``` ## Input variants The DatePicker supports different visual variants for the input field. ```razor
``` ```csharp public DateTime SelectedDateTime { get; set; } = DateTime.Now; public string SelectedDateTimeTextValue { get; set; } = DateTime.Now.ToString("dd/MM/yyyy HH:mm"); ``` ## Step Set `Step` to the number of minutes the time arrow buttons and the `Arrow Up`/`Arrow Down` keys move by. Under an hour, the minutes step (15 gives :00, :15, :30 and :45). From 60 upwards, the hours step instead (120 moves two hours at a time) and the minutes are shown as fixed text with no arrow buttons. The step must divide an hour (1, 2, 3, 4, 5, 6, 10, 12, 15, 20 or 30) or be a whole number of hours that divides a day (60, 120, 180, 240, 360, 480 or 720). A time typed into the field is kept as entered. When the browser's native picker is used, the step is passed on to it. ```razor ``` ```csharp public DateTime SelectedDateTime { get; set; } = DateTime.Now; public string SelectedDateTimeTextValue { get; set; } = DateTime.Now.ToString("dd/MM/yyyy HH:mm"); ``` ## Dense DateTime picker Set `Dense` for a more compact input with a smaller height and text size. Every single-line input shares the same dense height, so they line up when used side by side. ```razor ``` ```csharp public DateTime SelectedDateTime { get; set; } = DateTime.Now; public string SelectedDateTimeTextValue { get; set; } = DateTime.Now.ToString("dd/MM/yyyy HH:mm"); ``` ## Disabled and readonly DateTime picker Use the `Disabled` and `ReadOnly` properties to restrict interaction with the datetime picker. ```razor
``` ```csharp public DateTime SelectedDateTime { get; set; } = DateTime.Now; public string SelectedDateTimeTextValue { get; set; } = DateTime.Now.ToString("dd/MM/yyyy HH:mm"); ``` ## Keyboard navigation Type a date and time into the field, or open the panel, which holds a calendar above an hour and minute picker. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the field. The panel stays closed, so you can tab straight past it. | | `Arrow Down` | Opens the panel and moves focus into it. | | `Enter` or `Space` | On the icon button beside the field: opens the panel and moves focus into it, or closes it. | | `Enter` | Commits a value typed into the field. | | `Escape` | Closes the panel and returns focus to the field. Works from the field and from inside the panel. | | `Tab` or `Shift + Tab` | Moves between the controls in the open panel. Focus stays in the panel until it is closed. | | `Arrow Left` or `Arrow Right` | Moves to the previous or next day. Moving past the start or end of the month turns the page. The two keys swap in a right to left layout. | | `Arrow Up` or `Arrow Down` | Moves to the same weekday in the previous or next week. | | `Home` or `End` | Moves to the first or last day of the week. | | `Pg.Up` or `Pg.Down` | Moves to the previous or next month. | | `Shift + Page Up` or `Shift + Page Down` | Moves to the previous or next year. | | `Enter` or `Space` | Selects the focused day. | | `Enter` or `Space` | On the month and year heading: switches to the list of months, then of years. Focus lands on the current one, and Tab moves between them. | | `Arrow Up` or `Arrow Down` | In the hour or minute field: increases or decreases the value by one, or moves to the next or previous step when Step is set. When Step is a whole number of hours, the minutes are fixed text and are skipped by Tab. | | `Enter` or `Space` | On an arrow button or the AM/PM button: presses it. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDateTimePicker Represents a date and time picker component that allows users to select and edit date and time values, supporting both 12-hour and 24-hour formats. | Parameter | Type | Description | | --- | --- | --- | | `Format` | `string?` | The .NET custom date/time format string used to display and parse `SelectedDateTime`. Leave unset to fall back to `DefaultDateTimeFormat` or `DefaultDateTimeFormat12Hour` depending on `Is12HourFormat`. | | `Is12HourFormat` | `bool?` | Gets or sets a value indicating whether the time should be displayed in 12-hour format. | | `Step` | `int` | Gets or sets the step, in minutes, that the time step buttons and Arrow Up/Arrow Down move the time by. Steps under an hour move the minutes (e.g. 15 gives :00, :15, :30, :45); steps of an hour or more move the hours (e.g. 120 steps two hours at a time) and the minutes show as fixed text. Must divide an hour or, for whole hours, a day. Defaults to 1. Typed times are not rounded to the step. | | `SelectedDateTime` | `DateTime` | The selected `DateTime` value. | | `SelectedDateTimeChanged` | `EventCallback` | The selected bound `DateTime` value. | | `Value` | `string?` | The `string` value displayed in the textbox to the user. | | `ValueChanged` | `EventCallback` | The `string` bound value displayed in the textbox to the user. | | `Placeholder` | `string?` | The placeholder text to display when no date is selected. Defaults to the localized `DateTimePicker_Placeholder` text ("Select a datetime"). | | `PreferNativePicker` | `bool?` | Overrides automatic device detection for whether the browser's native datetime picker should be used instead of the custom popover. Leave unset (`null`) to auto-detect based on the client platform (iOS and Android use the native picker by default). | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwDatePickerTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwDatePickerTheme` by hand. --- # TwDateTimeRangePicker > TwDateTimeRangePicker is a Blazor component for choosing a start and end date and time from one popover. Bind Value, set MinDate, MaxDate and Format. Documentation page: https://twblazor.com/datetime-range-picker ## Basic DateTime range picker Bind `SelectedRange` for a `KeyValuePair` value (`Key` = start, `Value` = end). Unlike [TwDateRangePicker](https://twblazor.com/date-range-picker.md)'s two-month popover, this shows one month plus a time editor at a time: pick the start date and time first, then the panel automatically moves on to the end - small enough to comfortably use on a phone. Shares its theme (`TwDatePickerTheme`) with [TwDatePicker](https://twblazor.com/date-picker.md) and [TwDateRangePicker](https://twblazor.com/date-range-picker.md). ```razor

@@bind-SelectedRange: @(SelectedRange.Key?.ToString("g") ?? "-") - @(SelectedRange.Value?.ToString("g") ?? "-")

``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## 12-hour format Set `Is12HourFormat` to display and edit the time with an AM/PM toggle instead of 24-hour time. ```razor ``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Step Set `Step` to the number of minutes the start and end time arrow buttons and the `Arrow Up`/`Arrow Down` keys move by. Under an hour, the minutes step (15 gives :00, :15, :30 and :45). From 60 upwards, the hours step instead (120 moves two hours at a time) and the minutes are shown as fixed text with no arrow buttons. The step must divide an hour (1, 2, 3, 4, 5, 6, 10, 12, 15, 20 or 30) or be a whole number of hours that divides a day (60, 120, 180, 240, 360, 480 or 720). A time typed into the field is kept as entered. When the browser's native picker is used, the step is passed on to it. ```razor ``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Min and max date Use the `MinDate` and `MaxDate` properties to restrict the selectable range. While picking the end date, days before the already-picked start are disabled too, so the end can never land before it. ```razor ``` ```csharp public KeyValuePair BoundedRange { get; set; } public DateTime MinDate { get; set; } = DateTime.Today; public DateTime MaxDate { get; set; } = DateTime.Today.AddDays(30); ``` ## Input variants The datetime range picker supports the same visual variants as the other text inputs. ```razor
``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Dense DateTime range picker Set `Dense` for a more compact input with a smaller height and text size. Every single-line input shares the same dense height, so they line up when used side by side. ```razor ``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Disabled and readonly DateTime range picker Use the `Disabled` and `ReadOnly` properties to restrict interaction with the datetime range picker. ```razor
``` ```csharp public KeyValuePair SelectedRange { get; set; } ``` ## Keyboard navigation The panel sets one end of the range at a time. The Start and End buttons at the top switch between them. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the field. The panel stays closed, so you can tab straight past it. | | `Arrow Down` | Opens the panel and moves focus into it. | | `Enter` or `Space` | On the icon button beside the field: opens the panel and moves focus into it, or closes it. | | `Enter` | Commits a value typed into the field. | | `Escape` | Closes the panel and returns focus to the field. Works from the field and from inside the panel. | | `Tab` or `Shift + Tab` | Moves between the controls in the open panel. Focus stays in the panel until it is closed. | | `Enter` or `Space` | On the Start or End button: switches to that end of the range. | | `Arrow Left` or `Arrow Right` | Moves to the previous or next day. Moving past the start or end of the month turns the page. The two keys swap in a right to left layout. | | `Arrow Up` or `Arrow Down` | Moves to the same weekday in the previous or next week. | | `Home` or `End` | Moves to the first or last day of the week. | | `Pg.Up` or `Pg.Down` | Moves to the previous or next month. | | `Shift + Page Up` or `Shift + Page Down` | Moves to the previous or next year. | | `Enter` or `Space` | Selects the focused day. | | `Enter` or `Space` | On the month and year heading: switches to the list of months, then of years. Focus lands on the current one, and Tab moves between them. | | `Arrow Up` or `Arrow Down` | In the hour or minute field: increases or decreases the value by one, or moves to the next or previous step when Step is set. When Step is a whole number of hours, the minutes are fixed text and are skipped by Tab. | | `Enter` or `Space` | On an arrow button or the AM/PM button: presses it. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDateTimeRangePicker Represents a date and time range picker that lets users select a start and end date/time pair from a single popover, one step at a time: the start date and time first, then the end. | Parameter | Type | Description | | --- | --- | --- | | `Placeholder` | `string?` | The placeholder text to display when no range is selected. | | `SelectedRange` | `KeyValuePair` | The selected date/time range: `Key` is the start, `Value` is the end. Either (or both) may be `null` - both null means no range has been started yet, and a non-null `Key` with a null `Value` means only the start has been picked so far. `Key` is always less than or equal to `Value` when both are set. | | `SelectedRangeChanged` | `EventCallback>` | The bound `SelectedRange` value; invoked whenever it changes, including after only the start has been picked (`Value` still `null`) so callers can reflect an in-progress selection. | | `Value` | `string?` | The `string` value displayed in the textbox to the user. | | `ValueChanged` | `EventCallback` | The `string` bound value displayed in the textbox to the user. | | `Step` | `int` | Gets or sets the step, in minutes, that the time step buttons and Arrow Up/Arrow Down move the start and end times by. Steps under an hour move the minutes (e.g. 15 gives :00, :15, :30, :45); steps of an hour or more move the hours (e.g. 120 steps two hours at a time) and the minutes show as fixed text. Must divide an hour or, for whole hours, a day. Defaults to 1. Typed times are not rounded to the step. | | `Is12HourFormat` | `bool?` | Gets or sets a value indicating whether the time should be displayed in 12-hour format. Has no effect when `Format` is explicitly set. | | `Format` | `string?` | The .NET custom date/time format string used to display and parse each side of `SelectedRange`. Leave unset to fall back to `DefaultDateTimeFormat` or `DefaultDateTimeFormat12Hour` depending on `Is12HourFormat`. | | `RangeSeparator` | `string?` | The separator inserted between the two date/times in `Value`. Leave unset to fall back to `DefaultRangeSeparator` (default " - "). | | `MinDate` | `DateTime?` | The earliest selectable date (inclusive). Days before this are disabled in the calendar and rejected when typed; the Previous month button is also disabled once it's reached. | | `MaxDate` | `DateTime?` | The latest selectable date (inclusive). Days after this are disabled in the calendar and rejected when typed; the Next month button is also disabled once it's reached. | | `BodyClasses` | `string` | Gets or sets the CSS class names to apply to the body element of the component. | | `PreferNativePicker` | `bool?` | Overrides automatic device detection for whether the browser's native picker should be used instead of the custom popover. Leave unset (`null`) to auto-detect based on the client platform (iOS and Android use the native picker by default). | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwDatePickerTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwDatePickerTheme` by hand. --- # TwDialogProvider > TwDialog is a Blazor dialog service for modal windows. Open any component with ITwDialogService.ShowAsync, return data, and set position, size and behaviour. Documentation page: https://twblazor.com/dialog For example, to darken the backdrop further and use fully rounded dialogs by default: ```csharp builder.Services.AddTwBlazor(options => { options.Theme.Dialog.Backdrop = "fixed inset-0 z-[110] flex p-4 bg-black/70 overflow-y-auto"; // Darker backdrop options.Theme.Dialog.DialogRounded = Rounded.Full; // Fully rounded dialogs }, Theme.DefaultTheme); ``` ## Setup The Dialog service shows arbitrary Blazor components as modal dialogs, wrapped in a themed `TwDialog` chrome (backdrop, header, title, close button). To use dialogs, add the `TwDialogProvider` component to your app and inject the `ITwDialogService`. ##### 1. Add TwDialogProvider to your layout Place the `` component in your main layout file (e.g., MainLayout.razor or App.razor): ```razor ``` ##### 2. Register the services The dialog service is registered automatically when you call `AddTwBlazor()` with your configured theme (see [Get Started](https://twblazor.com/get-started.md) for the full theme setup): ```csharp builder.Services.AddTwBlazor(_ => { }, Theme.CreateDefaultTheme); ``` ##### 3. Inject the service in your component ```csharp @inject ITwDialogService DialogService ``` ## Basic usage Dialog content is a normal Blazor component. Show it with `ShowAsync()`, passing a title and any `TwDialogParameters` the content needs. Inside the content component, a cascaded `TwDialogInstance` lets it close (or cancel) itself. ```razor @if (confirmResult is not null) {

Result: @confirmResult

} ``` ```csharp private async Task ShowConfirmDialog() { var reference = await DialogService.ShowAsync("Confirm Action", new TwDialogParameters { ["Message"] = "Are you sure you want to continue?" }); var result = await reference.Result; confirmResult = result is { Canceled: false } ? "Confirmed" : "Cancelled"; } ``` ## Returning data A dialog can return more than a boolean. Call `DialogInstance.Close(data)` with any value, then read it back with `reference.GetReturnValueAsync()`. ```razor @if (promptResult is not null) {

Saved: @promptResult

} ``` ```csharp private async Task ShowPromptDialog() { var reference = await DialogService.ShowAsync("Edit Name", new TwDialogParameters { ["Label"] = "Name", ["InitialValue"] = userName }); var name = await reference.GetReturnValueAsync(); if (!string.IsNullOrEmpty(name)) { userName = name; promptResult = name; } } ``` ## Position Pass a `TwDialogOptions` with a `Position` to control where the dialog appears on screen. ```razor
@foreach (DialogPosition position in Enum.GetValues()) { }
``` ```csharp private Task ShowAtPosition(DialogPosition position) { return DialogService.ShowAsync("Positioned Dialog", new TwDialogParameters { ["Message"] = $"This dialog is positioned at {position}." }, new TwDialogOptions { Position = position }); } ``` ## Sizing Use `MaxWidth` for a responsive width breakpoint, or `FullScreen` to fill the entire viewport. ```razor
@foreach (DialogMaxWidth maxWidth in Enum.GetValues()) { }
``` ```csharp private Task ShowWithMaxWidth(DialogMaxWidth maxWidth) { return DialogService.ShowAsync("Sized Dialog", new TwDialogParameters { ["Message"] = $"This dialog uses the {maxWidth} width." }, new TwDialogOptions { MaxWidth = maxWidth }); } private Task ShowFullScreenDialog() { return DialogService.ShowAsync("Full Screen Dialog", new TwDialogParameters { ["Message"] = "This dialog fills the entire screen." }, new TwDialogOptions { FullScreen = true }); } ``` ## Behavior options `NoHeader` hides the title bar entirely, and combining `BackdropClick`, `CloseOnEscapeKey`, and `CloseButton` (all set to `false`) produces a dialog that can only be closed by its own content. ```razor
``` ```csharp private Task ShowNoHeaderDialog() { return DialogService.ShowAsync( parameters: new TwDialogParameters { ["Message"] = "This dialog has no header or title." }, options: new TwDialogOptions { NoHeader = true }); } private Task ShowNonDismissibleDialog() { return DialogService.ShowAsync("Not Dismissible", new TwDialogParameters { ["Message"] = "This dialog can only be closed using its own buttons." }, new TwDialogOptions { BackdropClick = false, CloseOnEscapeKey = false, CloseButton = false }); } ``` ## Keyboard navigation Opening a dialog moves focus into it and makes the page behind it unreachable. Closing it returns focus to the control that opened it. | Key | What it does | | --- | --- | | `Tab` | Moves to the next control in the dialog. From the last control it wraps to the first. | | `Shift + Tab` | Moves to the previous control in the dialog. From the first control it wraps to the last. | | `Escape` | Closes the dialog, wherever focus is. If a picker or a select list is open inside the dialog, the first press closes that and the next press closes the dialog. Has no effect when CloseOnEscapeKey is off. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDialog Renders the backdrop, positioning, and chrome (header, title, close button) around dialog content shown via `ITwDialogService`. | Parameter | Type | Description | | --- | --- | --- | | `Reference` | `ITwDialogReference` | Gets or sets the dialog reference this chrome renders content for. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwDialogProvider Hosts and renders dialogs shown through `ITwDialogService`. No parameters. ## Theme Styled by `TwDialogTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwDialogTheme` by hand. --- # TwDirectionProvider > TwDirectionProvider sets a Blazor app, or part of a page, to right to left or left to right, mirroring layout and arrow keys for Arabic and Hebrew. Documentation page: https://twblazor.com/direction-provider ## Right to left Wrap content in a `TwDirectionProvider` and set `Direction`. Everything inside is mirrored: text aligns to the other side, icons and labels swap places, panels open from the other edge, and the Left and Right arrow keys swap so they keep following what is on screen. ```razor

معلومات الملف الشخصي.

إعدادات الأمان.

سجل الفواتير.

``` ```csharp private string name = string.Empty; private bool notifications = true; private int page = 1; ``` ## Follow the language Leave `Direction` unset and the provider follows the language the application is running in: right to left for a culture such as Arabic, Hebrew, Persian or Urdu, left to right for everything else. Wrap the layout once and the whole application turns with the culture. Keep the toast and dialog providers inside it, so toasts and dialogs turn too. ```razor @* MainLayout.razor *@ @Body ``` To pin the direction whatever the culture, set it once in `AddTwBlazor`. ```csharp builder.Services.AddTwBlazor(options => { options.Localization.Direction = TextDirection.RightToLeft; }, Theme.CreateTheme); ``` ## Without the provider The provider is a convenience. What the styles react to is the `dir` attribute, so an application that already sets it on the `html` element does not need one. Set it from the same culture twblazor reads, so the layout and the arrow keys agree. ```razor @* App.razor *@ @inject ITwLocalizer Localizer ``` The `dir` attribute has to be there. Setting `direction: rtl` in CSS alone turns the text but not the parts of the theme that are mirrored with Tailwind's `rtl:` variant. ## One part of a page Providers nest, and the nearest one wins. Use this for a left to right island in a right to left page, or the other way round. ```razor هذا التنبيه يُقرأ من اليمين إلى اليسار. This alert reads left to right. ``` ```csharp private int volume = 40; ``` ## What is mirrored Mirroring follows the reading direction, so anything described as Left or Right means the start or end of the line. ## Your own theme and markup The default theme uses Tailwind's logical classes, which follow the direction by themselves. If you keep your own copy of `Theme.cs`, or write your own markup around the components, use them too. A sideways transform has no logical form, so pair it with the `rtl:` variant, as the theme does for the switch thumb: `peer-checked:translate-x-full rtl:peer-checked:-translate-x-full`. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwDirectionProvider Sets the direction, left to right or right to left, of everything inside it. It writes the `dir` attribute the styles react to and tells the components inside which way their arrow keys should move. | Parameter | Type | Description | | --- | --- | --- | | `Direction` | `TextDirection?` | Gets or sets the direction of the content. Leave unset to follow an enclosing provider, and failing that the current language. | | `ChildContent` | `RenderFragment?` | Gets or sets the content the direction applies to. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # TwFileUpload > TwFileUpload is a Blazor file upload component. Bind Files, restrict types with AllowedFileTypes, allow Multiple files and handle OnChange. Documentation page: https://twblazor.com/file-upload ## Basic file upload Use `Icon`, `Label`, `Variant` and `Color` to style the upload button, and `Multiple` to allow more than one file. ```razor
``` ## Binding Bind to access the list of selected files. ```razor
Selected files
    @foreach (var f in boundFiles ?? Enumerable.Empty()) {
  • @f.Name (@(f.Size) bytes)
  • }
``` ```csharp private List? boundFiles = new(); ``` ## Accept (allowed file types) Use `AllowedFileTypes` to restrict which file types can be selected, via the `accept` attribute. ```razor
``` ## Keyboard navigation The upload control is a native file input. Each chosen file is listed with its own remove button, and choosing or removing a file is announced. | Key | What it does | | --- | --- | | `Tab` | Moves to the upload control, then to each file's remove button. | | `Enter` or `Space` | On the upload control: opens the system file dialog. | | `Enter` or `Space` | On a remove button: removes that file. Focus returns to the upload control. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwFileUpload Represents a file upload input component that allows users to select and upload files. This component provides properties for handling file selection events and configuring multiple file selection. It inherits from `TwBlazorInputComponentBase`, which provides common input component functionality such as labeling and disabled state management. | Parameter | Type | Description | | --- | --- | --- | | `Icon` | `Icon?` | The icon displayed at the start of the input, the default is `Cloud_Upload`, if you would like this blank explicity set this to null. | | `Variant` | `ButtonVariant?` | The button variant style applied to the upload input. | | `Color` | `Color?` | | | `Multiple` | `bool` | Gets or sets a value indicating whether the file input should allow multiple file selection. When true, the user can select more than one file; when false, only a single file can be selected. | | `AllowedFileTypes` | `IEnumerable?` | Optional list of allowed file types (MIME types or extensions) to restrict selectable files in the UI. Example values: new[]{".png",".jpg","image/pdf","application/pdf"} These values will be joined and applied to the input's "accept" attribute. | | `OnChange` | `EventCallback` | Gets or sets the event callback that is invoked when the user selects one or more files using the file input. | | `Files` | `List?` | Two-way bindable file list. Parent can bind this with @bind-Files to keep synchronized. | | `FilesChanged` | `EventCallback?>` | | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwButtonTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwButtonTheme` by hand. --- # TwFooter > TwFooter is an accessible Blazor page footer with columns of links, a brand slot, free-form content and a bottom row for copyright and legal links. Documentation page: https://twblazor.com/footer ## Basic usage `TwFooter` draws a page footer from data. Pass `Sections`, each a title and its links, and every section becomes a column. A link can be written as a label and an address, so a whole footer fits in a few lines. ```razor ``` ```csharp private readonly FooterSection[] _sections = [ new("Product", [("Features", "/footer"), ("Pricing", "/footer"), ("Changelog", "/footer")]), new("Company", [("About", "/footer"), ("Careers", "/footer"), ("Contact", "/footer")]), new("Resources", [("Documentation", "/footer"), ("Guides", "/footer"), ("Support", "/footer")]), new("Legal", [("Privacy", "/footer"), ("Terms", "/footer")]) ]; ``` ## Copyright and legal links `Copyright` and `BottomLinks` fill a row along the bottom, under a divider. Either can be used alone, and with no sections the row is the whole footer. ```razor ``` ```csharp private readonly FooterLink[] _legal = [("Privacy", "/footer"), ("Terms", "/footer"), ("Cookies", "/footer")]; ``` ```razor ``` ## Brand, content and extras Three slots take your own markup. `BrandContent` sits above the sections, for a logo and a line about the company. `ChildContent` comes after the sections, for anything the data model does not cover, such as a newsletter form. `BottomContent` joins the bottom row, for social links or a language picker. ```razor

Acme

Tools that help small teams ship faster.

@(subscribed ? "Thanks. This form is only an example, so nothing was sent." : string.Empty)

``` ## Icons and links that open elsewhere Use the full `FooterLink` to give a link an `Icon` or set `OpensInNewTab`. A link that opens in a new tab tells assistive technology so, and is given `rel="noopener noreferrer"`. ```razor ``` ```csharp private readonly FooterSection[] _community = [ new("Community", [ new("GitHub", "https://github.com/twblazor/twblazor", Icon.Github, OpensInNewTab: true), new("News feed", "/footer", Icon.Rss) ]), new("Help", [("Documentation", "/footer"), new FooterLink("Status page", "https://example.com/status", OpensInNewTab: true)]) ]; ``` ## Heading level Section titles are real headings, so they appear in a screen reader's heading list. They are level 2 by default. Set `HeadingLevel` so they follow on from the headings above the footer on your page. ```razor ``` ## Accessibility The component renders a `footer` element, which is the page's content information landmark as long as it is not inside an `article`, `section` or `main`. Use one per page. The sections sit in a navigation landmark named "Footer links"; change the name with `NavigationLabel` if the page has another landmark with the same name. Each section is a heading followed by a list named by that heading, so the group and the number of links in it are announced. Give the footer itself a name with `AriaLabel` if the page has more than one. Every link is an ordinary tab stop in reading order. The focus outline takes the footer's own text color, so it stays visible on any background a theme gives it. Icons beside links are decorative and hidden from assistive technology. ## Keyboard navigation The footer is the page's content information landmark. Its sections sit in a navigation landmark, each a heading and a list of ordinary links. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves to the next or previous link. | | `Enter` | Follows the focused link. A link that opens in a new tab says so before you follow it. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwFooter A page footer: columns of titled links, an optional brand area above them, free-form content, and a bottom row for a copyright line and a few legal links. Every part is optional, so it works as a one-line footer or a full site map. | Parameter | Type | Description | | --- | --- | --- | | `Sections` | `IReadOnlyList` | Gets or sets the titled groups of links, each drawn as a column. | | `BottomLinks` | `IReadOnlyList` | Gets or sets the links along the bottom row, typically legal pages such as privacy and terms. | | `Copyright` | `string?` | Gets or sets the copyright line shown in the bottom row. | | `BrandContent` | `RenderFragment?` | Gets or sets content shown above the sections, such as a logo and a short description. | | `ChildContent` | `RenderFragment?` | Gets or sets free-form content, rendered after the sections and before the bottom row. | | `BottomContent` | `RenderFragment?` | Gets or sets extra content for the bottom row, after the copyright line and the bottom links, such as social media links or a language picker. | | `HeadingLevel` | `int` | Gets or sets the heading level of the section titles, from 1 to 6. | | `NavigationLabel` | `string?` | Gets or sets the accessible name of the navigation landmark that holds the sections. Defaults to the localized `Footer_Label` text ("Footer links"). | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwFooterTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwFooterTheme` by hand. --- # Get Started > Install twblazor in a Blazor Server or WebAssembly app: add the NuGet package, imports, providers and a theme, register AddTwBlazor and build your Tailwind CSS. Documentation page: https://twblazor.com/get-started Make it match your brand TwBlazor is fully themeable. Use the [Theme builder](https://twblazor.com/theme) to pick your brand colors, choose only the components you need and copy a ready-made `Theme.cs` to use in step 6. ## Blazor Server ### 1. Create the project Scaffold a new Blazor Web App using the default Interactive Server render mode. This creates a single project. Replace `{YourProjectName}` with your own project's name. ```bash dotnet new blazor -o {YourProjectName} ``` This only scaffolds the project itself, so you won't see a `.sln` file yet - that's expected. If you want one, e.g. to open the project in Visual Studio or Rider, create it with: ```bash cd {YourProjectName} dotnet new sln dotnet sln add {YourProjectName}.csproj ``` ### 2. Install the twblazor NuGet package Install the [twblazor NuGet package](https://www.nuget.org/packages/twblazor) in the `{YourProjectName}` project. ```bash dotnet add package twblazor --version 2.1.2 ``` ### 3. Add to App.razor In `{YourProjectName}/Components/App.razor`, include two stylesheet links along with the default content. The first is for TwIcon, which uses Bootstrap Icons - while you can link to the Bootstrap Icons CDN directly, we include the icons in our package for convenience. The second is for **your own** Tailwind build, which will contain both TwBlazor's classes and the theme classes you configure in step 6. It doesn't exist yet, so it'll 404 until you build it in step 8; that's expected. ```razor ``` At the bottom of the body you'll also need to include the links to twblazor.js. ```razor ``` ### 4. Add to _Imports.razor In `{YourProjectName}/Components/_Imports.razor` you'll need to add references to the following: ```razor @using TwBlazor.Components @using TwBlazor.Enums @using TwBlazor ``` ### 5. Add the TwBlazor providers TwBlazor toasts and dialogs require you to add the following to the top of `{YourProjectName}/Components/Layout/MainLayout.razor`. ```razor ``` ### 6. Add a TwTheme TwBlazor requires you to set up a few simple configuration classes for theming. Since Tailwind CSS cannot compile classes from .DLLs, you configure the classes in your own project, where your own Tailwind build can see them. Create a `Theme.cs` file at the root of the `{YourProjectName}` project. ```csharp public static TwBlazorTheme CreateDefaultTheme() { var flexbox = new TwBlazorFlexbox { Row = "flex-row", RowReverse = "flex-row-reverse", Col = "flex-col", ColReverse = "flex-col-reverse", Wrap = "flex-wrap", NoWrap = "flex-nowrap", WrapReverse = "flex-wrap-reverse", Grow = "grow", GrowNone = "grow-0", Shrink = "shrink", ShrinkNone = "shrink-0", Flex1 = "flex-1", Justify = new() { Start = "justify-start", Center = "justify-center", End = "justify-end", Between = "justify-between", Around = "justify-around", Evenly = "justify-evenly" }, Align = new() { Start = "items-start", Center = "items-center", End = "items-end", Stretch = "items-stretch", Baseline = "items-baseline" }, AlignContent = new() { Start = "content-start", Center = "content-center", End = "content-end", Between = "content-between", Around = "content-around", Evenly = "content-evenly", Stretch = "content-stretch" }, AlignSelf = new() { Start = "self-start", Center = "self-center", End = "self-end", Stretch = "self-stretch", Baseline = "self-baseline" } }; var anchor = new TwAnchorPosition { Center = $"{flexbox.Align.Center} {flexbox.Justify.Center}", CenterLeft = $"{flexbox.Align.Center} {flexbox.Justify.Start}", CenterRight = $"{flexbox.Align.Center} {flexbox.Justify.End}", TopCenter = $"{flexbox.Align.Start} {flexbox.Justify.Center}", TopLeft = $"{flexbox.Align.Start} {flexbox.Justify.Start}", TopRight = $"{flexbox.Align.Start} {flexbox.Justify.End}", BottomCenter = $"{flexbox.Align.End} {flexbox.Justify.Center}", BottomLeft = $"{flexbox.Align.End} {flexbox.Justify.Start}", BottomRight = $"{flexbox.Align.End} {flexbox.Justify.End}", }; var text = new TwTextColor { Light = { Primary = "text-purple-200", Accent = "text-fuchsia-200", Success = "text-green-200", Danger = "text-red-200", Warning = "text-yellow-200", Info = "text-blue-200", Light = "text-white", Dark = "text-gray-200" }, Medium = { Primary = "text-purple-600", Accent = "text-fuchsia-700", Success = "text-green-800", Danger = "text-red-700", Warning = "text-yellow-800", Info = "text-blue-600", Light = "text-gray-100", Dark = "text-gray-950", }, Dark = { Primary = "text-purple-900", Accent = "text-fuchsia-900", Success = "text-green-900", Danger = "text-red-900", Warning = "text-yellow-900", Info = "text-blue-900", Light = "text-gray-300", Dark = "text-gray-900" } }; var darkText = new TwTextColor { Light = { Primary = "dark:text-purple-200", Accent = "dark:text-fuchsia-200", Success = "dark:text-green-200", Danger = "dark:text-red-200", Warning = "dark:text-yellow-200", Info = "dark:text-blue-200", Dark = "dark:text-gray-200" }, Medium = { Primary = "dark:text-purple-600", Accent = "dark:text-fuchsia-600", Success = "dark:text-green-600", Danger = "dark:text-red-600", Warning = "dark:text-yellow-600", Info = "dark:text-blue-600", Light = "dark:text-white", Dark = "dark:text-gray-950", }, Dark = { Primary = "dark:text-purple-900", Accent = "dark:text-fuchsia-900", Success = "dark:text-green-900", Danger = "dark:text-red-900", Warning = "dark:text-yellow-900", Info = "dark:text-blue-900", Dark = "dark:text-gray-900" } }; var borderColors = new TwBlazorPalette { Primary = "border-purple-600 dark:border-purple-500", Accent = "border-fuchsia-600 dark:border-fuchsia-400", Success = "border-green-600 dark:border-green-400", Danger = "border-red-600 dark:border-red-400", Warning = "border-yellow-700 dark:border-yellow-400", Info = "border-blue-600 dark:border-blue-400", Light = "border-gray-100 dark:border-gray-700", Dark = "border-gray-900 dark:border-gray-700" }; var hoverColors = new TwBlazorPalette { Primary = "hover:bg-purple-50 dark:hover:bg-purple-900/20", Accent = "hover:bg-fuchsia-50 dark:hover:bg-fuchsia-900/20", Success = "hover:bg-green-50 dark:hover:bg-green-900/20", Danger = "hover:bg-red-50 dark:hover:bg-red-900/20", Warning = "hover:bg-yellow-50 dark:hover:bg-yellow-900/20", Info = "hover:bg-blue-50 dark:hover:bg-blue-900/20", Light = "hover:bg-gray-100/10", Dark = "hover:bg-gray-900/10 dark:hover:bg-white/10" }; var background = new TwBackgroundColor { Lightest = new() { Primary = $"bg-purple-50", Accent = $"bg-fuchsia-50", Success = $"bg-green-50", Danger = $"bg-red-50", Warning = $"bg-yellow-50", Info = $"bg-blue-50", Light = $"bg-white", Dark = $"bg-gray-50" }, Light = new() { Primary = $"bg-purple-200", Accent = $"bg-fuchsia-200", Success = $"bg-green-200", Danger = $"bg-red-200", Warning = $"bg-yellow-200", Info = $"bg-blue-200", Light = $"bg-white", Dark = $"bg-gray-200" }, Medium = new() { Primary = $"bg-purple-600", Accent = $"bg-fuchsia-600", Success = $"bg-green-700", Danger = $"bg-red-600", Warning = $"bg-yellow-600", Info = $"bg-blue-600", Light = $"bg-gray-100", Dark = $"bg-gray-600", }, Dark = new() { Primary = $"bg-purple-900", Accent = $"bg-fuchsia-900", Success = $"bg-green-900", Danger = $"bg-red-900", Warning = $"bg-yellow-900", Info = $"bg-blue-900", Light = $"bg-gray-300", Dark = $"bg-gray-900" }, Darkest = new() { Primary = $"bg-purple-950", Accent = $"bg-fuchsia-950", Success = $"bg-green-950", Danger = $"bg-red-950", Warning = $"bg-yellow-950", Info = $"bg-blue-950", Light = $"bg-gray-950", Dark = $"bg-black" } }; var darkBackground = new TwBackgroundColor { Lightest = new() { Primary = $"dark:bg-purple-50", Accent = $"dark:bg-fuchsia-50", Success = $"dark:bg-green-50", Danger = $"dark:bg-red-50", Warning = $"dark:bg-yellow-50", Info = $"dark:bg-blue-50", Dark = $"dark:bg-gray-50" }, Light = new() { Primary = $"dark:bg-purple-200", Accent = $"dark:bg-fuchsia-200", Success = $"dark:bg-green-200", Danger = $"dark:bg-red-200", Warning = $"dark:bg-yellow-200", Info = $"dark:bg-blue-200", Dark = $"dark:bg-gray-200", }, Medium = new() { Primary = $"dark:bg-purple-600", Accent = $"dark:bg-fuchsia-600", Success = $"dark:bg-green-600", Danger = $"dark:bg-red-600", Warning = $"dark:bg-yellow-600", Info = $"dark:bg-blue-600", Light = $"dark:bg-white", Dark = $"dark:bg-gray-600", }, Dark = new() { Primary = $"dark:bg-purple-900", Accent = $"dark:bg-fuchsia-900", Success = $"dark:bg-green-900", Danger = $"dark:bg-red-900", Warning = $"dark:bg-yellow-900", Info = $"dark:bg-blue-900", Dark = $"dark:bg-gray-900", }, Darkest = new() { Primary = $"dark:bg-purple-950", Accent = $"dark:bg-fuchsia-950", Success = $"dark:bg-green-950", Danger = $"dark:bg-red-950", Warning = $"dark:bg-yellow-950", Info = $"dark:bg-blue-950", Dark = $"dark:bg-black", } }; var checkBoxRadioButtonColors = new TwBlazorPalette() { Primary = "checked:bg-purple-600 checked:border-purple-600 dark:checked:bg-purple-500 dark:checked:border-purple-500", Accent = "checked:bg-fuchsia-600 checked:border-fuchsia-600 dark:checked:bg-fuchsia-500 dark:checked:border-fuchsia-500", Success = "checked:bg-green-600 checked:border-green-600 dark:checked:bg-green-500 dark:checked:border-green-500", Danger = "checked:bg-red-600 checked:border-red-600 dark:checked:bg-red-500 dark:checked:border-red-500", Warning = "checked:bg-yellow-700 checked:border-yellow-700 dark:checked:bg-yellow-500 dark:checked:border-yellow-500", Info = "checked:bg-blue-600 checked:border-blue-600 dark:checked:bg-blue-500 dark:checked:border-blue-500", Light = "checked:bg-white checked:border-gray-900 dark:checked:bg-white dark:checked:border-gray-500", Dark = "checked:bg-gray-900 checked:border-gray-900 dark:checked:bg-gray-900 dark:checked:border-gray-900" }; var neutralSurface = new TwSurfacePalette { Background = "bg-[oklch(100%_0_0)] dark:bg-[oklch(25.33%_0.016_252.42)]", Body = "bg-[oklch(98.5%_0_0)] dark:bg-[oklch(22.2%_0.015_253)]", BackgroundSubtle = "bg-[oklch(98%_0_0)] dark:bg-[oklch(23.26%_0.014_253.1)]", Border = "border-[oklch(92%_0_0)] dark:border-[oklch(21.15%_0.012_254.09)]", BorderSubtle = "border-[oklch(98%_0_0)] dark:border-[oklch(23.26%_0.014_253.1)]", Hover = "hover:bg-[oklch(98%_0_0)] dark:hover:bg-[oklch(23.26%_0.014_253.1)]", Elevated = "bg-[oklch(97%_0_0)] dark:bg-[oklch(34%_0.018_253)]", Overlay = "bg-[oklch(100%_0_0)] dark:bg-[oklch(40%_0.016_253)]", BorderStrong = "border-[oklch(21%_0.006_285.885)]/50 dark:border-[oklch(97.807%_0.029_256.847)]/45" }; var neutralText = new TwNeutralTextPalette { Heading = "text-[oklch(21%_0.006_285.885)] dark:text-[oklch(97.807%_0.029_256.847)]", Secondary = "text-[oklch(40%_0.006_285.885)] dark:text-[oklch(88%_0.02_256.847)]", Muted = "text-[oklch(50%_0.006_285.885)] dark:text-[oklch(78%_0.02_256.847)]", Subtle = "text-[oklch(55%_0.006_285.885)] dark:text-[oklch(68%_0.02_256.847)]" }; // One height for every single-line input (and the controls laid out beside them, e.g. pagination), // so they all line up whichever component renders them. var inputHeight = "h-10"; var inputDenseHeight = "h-8"; // Single focus language for every focusable surface: a 2px primary ring. The inset form is for rows // that sit flush against their container's edge and would otherwise have the ring clipped. var focusRing = "focus-visible:ring-2 focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400"; var focusRingInset = "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400"; // Neutral fills reused wherever a component needs a recessed track, a selected row or a pressed state. var neutralTrack = "bg-[oklch(95%_0_0)] dark:bg-[oklch(21.15%_0.012_254.09)]"; // A recessed track that stays visible on a white card: progress and slider tracks carry the value, so // they need more contrast than the page-chrome fill above. var neutralTrackStrong = "bg-[oklch(91%_0_0)] dark:bg-[oklch(32%_0.016_253)]"; var neutralHoverText = "hover:text-[oklch(21%_0.006_285.885)] dark:hover:text-[oklch(97.807%_0.029_256.847)]"; var neutralRowHover = "hover:bg-[oklch(21%_0.006_285.885)]/5 dark:hover:bg-[oklch(97.807%_0.029_256.847)]/8"; var neutralHoverFill = "hover:bg-[oklch(21%_0.006_285.885)]/10 dark:hover:bg-[oklch(97.807%_0.029_256.847)]/10"; var neutralHairlineRing = "ring-1 ring-inset ring-[oklch(21%_0.006_285.885)]/10 dark:ring-[oklch(97.807%_0.029_256.847)]/15"; var disabledInk = "text-[oklch(21%_0.006_285.885)]/40 dark:text-[oklch(97.807%_0.029_256.847)]/40"; var inputLabelText = $"text-xs font-normal tracking-wide {neutralText.Muted}"; var display = new TwBlazorDisplay { Block = "block", InlineBlock = "inline-block", Flex = "flex", InlineFlex = "inline-flex", Grid = "grid", InlineGrid = "inline-grid", Hidden = "hidden", Contents = "contents", ScreenReaderOnly = "sr-only" }; var spacing = new TwBlazorSpacing { Gap = new() { Sm = "gap-1", Md = "gap-2", Lg = "gap-3", Xl = "gap-4" }, InteractiveRowPadding = "px-4 py-3", PushEnd = "ms-auto", Padding = new() { Sm = "p-1", Md = "p-2", Lg = "p-3", Xl = "p-4" }, Margin = new() { Sm = "m-1", Md = "m-2", Lg = "m-3", Xl = "m-4" }, MarginTop = new() { Sm = "mt-1", Md = "mt-2", Lg = "mt-3", Xl = "mt-4" }, MarginBottom = new() { Sm = "mb-1", Md = "mb-2", Lg = "mb-3", Xl = "mb-4" }, PaddingTop = new() { Sm = "pt-1", Md = "pt-2", Lg = "pt-3", Xl = "pt-4" }, PaddingStart = new() { Sm = "ps-1", Md = "ps-2", Lg = "ps-3", Xl = "ps-4" }, MarginStart = new() { Sm = "ms-1", Md = "ms-2", Lg = "ms-3", Xl = "ms-4" }, MarginEnd = new() { Sm = "me-1", Md = "me-2", Lg = "me-3", Xl = "me-4" } }; var interaction = new TwBlazorInteraction { DisabledOpacity = "opacity-40", PointerCursor = "cursor-pointer", DisabledCursor = "cursor-not-allowed", ReadonlyCursor = "cursor-default", PointerEventsNone = "pointer-events-none", FocusOutlineNone = "focus:outline-hidden" }; var sizing = new TwBlazorSizing { FullWidth = "w-full", FullHeight = "h-full", Full = "w-full h-full", MinWidthNone = "min-w-0", Icon = new() { Xs = "size-3", Sm = "size-4", Md = "size-5", Lg = "size-6", Xl = "size-8" } }; var overflow = new TwBlazorOverflow { Hidden = "overflow-hidden" }; var transition = new TwBlazorTransition { Colors = "transition-colors motion-reduce:transition-none", Transform = "transition-transform motion-reduce:transition-none", EaseInOut = "ease-in-out", DurationFast = "duration-200", DurationSlow = "duration-300" }; transition.ColorsFast = $"{transition.Colors} {transition.DurationFast}"; transition.ColorsSlow = $"{transition.Colors} {transition.DurationSlow}"; transition.TransformFast = $"{transition.Transform} {transition.DurationFast}"; transition.TransformSlow = $"{transition.Transform} {transition.DurationSlow}"; var typography = new TwBlazorTypography { Size = new() { Xs = "text-xs", Sm = "text-sm", Base = "text-base", Lg = "text-lg" }, Weight = new() { Medium = "font-medium", Semibold = "font-semibold" }, AlignCenter = "text-center", WrapBreakWord = "wrap-break-word" }; var rounded = new TwBlazorRounded { None = "rounded-none", Sm = "rounded-sm", Md = "rounded", Lg = "rounded-lg", Full = "rounded-full", DefaultRounded = Rounded.Lg, RoundedTop = new() { None = "rounded-t-none", Sm = "rounded-t-sm", Md = "rounded-t", Lg = "rounded-t-lg", Full = "rounded-t-full" }, RoundedBottom = new() { None = "rounded-b-none", Sm = "rounded-b-sm", Md = "rounded-b", Lg = "rounded-b-lg", Full = "rounded-b-full" }, RoundedStart = new() { None = "rounded-s-none", Sm = "rounded-s-sm", Md = "rounded-s", Lg = "rounded-s-lg", Full = "rounded-s-full" }, RoundedEnd = new() { None = "rounded-e-none", Sm = "rounded-e-sm", Md = "rounded-e", Lg = "rounded-e-lg", Full = "rounded-e-full" } }; var shadows = new TwBlazorShadow { None = "shadow-none", Sm = "shadow-sm", Md = "shadow", Lg = "shadow-lg", Xl = "shadow-xl", HoverSm = "hover:shadow-sm", HoverMd = "hover:shadow", HoverLg = "hover:shadow-xl", ActiveMd = "active:shadow", DefaultShadow = Shadow.Sm }; var borderWidth = new TwBlazorBorderWidth { None = "border-0", Thin = "border", Medium = "border-[1.2px]", Thick = "border-2", AccentEdge = "border-s-4" }; // Combined border home: one width scale plus semantic and neutral color, so a component theme // never has to reach into three separate places to build a border class. var border = new TwBlazorBorder { Width = borderWidth, Colors = borderColors, Neutral = new() { Base = neutralSurface.Border, Subtle = neutralSurface.BorderSubtle, Strong = neutralSurface.BorderStrong } }; var positioning = new TwBlazorPositioning { Static = "static", Relative = "relative", Absolute = "absolute", Fixed = "fixed", Sticky = "sticky" }; var inset = new TwBlazorInset { Top = "top-0", Bottom = "bottom-0", Start = "start-0", End = "end-0" }; var textTransform = new TwBlazorTextTransform { Uppercase = "uppercase", Lowercase = "lowercase", Capitalize = "capitalize", NormalCase = "normal-case" }; var transparentBackground = "bg-transparent"; var overlayTheme = new TwOverlayTheme { Popover = new TwPopoverTheme { Background = neutralSurface.Overlay, Border = $"{borderWidth.Thin} {neutralSurface.BorderStrong}", TimeRangeSize = $"w-56 {spacing.Padding.Md}", ColorSize = $"tw-color-picker-dialog w-64 {spacing.Padding.Lg}" }, Dialog = new TwDialogTheme { Background = neutralSurface.Background, Backdrop = $"{positioning.Fixed} inset-0 z-110 {display.Flex} overflow-y-auto overscroll-contain {spacing.Padding.Xl} bg-black/50", Surface = $"{positioning.Relative} {display.Flex} {flexbox.Col} {sizing.FullWidth} max-h-[calc(100vh-2rem)] {neutralText.Heading} {neutralSurface.Background}", Header = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Xl} {flexbox.ShrinkNone} {spacing.InteractiveRowPadding} {neutralSurface.Border}", Title = $"{typography.Size.Lg} {typography.Weight.Semibold}", CloseButton = string.Empty, Content = $"overflow-y-auto {spacing.InteractiveRowPadding}", FullScreen = $"{sizing.Full} max-w-none", FullWidth = sizing.FullWidth, SmallWidth = "sm:max-w-lg", MediumWidth = "sm:max-w-xl", LargeWidth = "sm:max-w-3xl" }, Tooltip = new TwTooltipTheme { Wrapper = $"{positioning.Relative} {display.InlineFlex} group", Bubble = $"{positioning.Absolute} z-130 w-max max-w-xs px-2 py-1 {typography.Size.Xs} {typography.Weight.Medium} {neutralText.Heading} hidden group-hover:block group-focus-visible:block group-has-[:focus-visible]:block group-data-[tw-tooltip-open]:block", Dismissed = "!hidden", Top = "bottom-full left-1/2 mb-2 -translate-x-1/2 after:absolute after:inset-x-0 after:top-full after:h-2 after:content-['']", Bottom = "top-full left-1/2 mt-2 -translate-x-1/2 after:absolute after:inset-x-0 after:bottom-full after:h-2 after:content-['']", Left = "end-full top-1/2 me-2 -translate-y-1/2 after:absolute after:inset-y-0 after:start-full after:w-2 after:content-['']", Right = "start-full top-1/2 ms-2 -translate-y-1/2 after:absolute after:inset-y-0 after:end-full after:w-2 after:content-['']", Arrow = $"{positioning.Absolute} size-2 rotate-45 pointer-events-none", ArrowTop = "-bottom-[5px] left-1/2 -translate-x-1/2 border-t-0 border-l-0", ArrowBottom = "-top-[5px] left-1/2 -translate-x-1/2 border-b-0 border-r-0", ArrowLeft = "-end-[5px] top-1/2 -translate-y-1/2 border-b-0 border-s-0 rtl:-rotate-45", ArrowRight = "-start-[5px] top-1/2 -translate-y-1/2 border-t-0 border-e-0 rtl:-rotate-45" } }; return new TwBlazorTheme { Anchor = anchor, Position = positioning, Inset = inset, Display = display, Flexbox = flexbox, Spacing = spacing, Sizing = sizing, Interaction = interaction, Border = border, TextTransform = textTransform, Transition = transition, Typography = typography, Overflow = overflow, Colors = new() { TextColors = text, DarkTextColors = darkText, HoverColors = hoverColors, Transparent = transparentBackground, LightBackground = background, DarkBackground = darkBackground, FocusRingBase = "focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-[oklch(100%_0_0)] dark:focus-visible:ring-offset-[oklch(25.33%_0.016_252.42)]", FocusColors = new() { Primary = "focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400", Accent = "focus-visible:ring-fuchsia-500 dark:focus-visible:ring-fuchsia-400", Success = "focus-visible:ring-green-600 dark:focus-visible:ring-green-400", Danger = "focus-visible:ring-red-500 dark:focus-visible:ring-red-400", Warning = "focus-visible:ring-yellow-500 dark:focus-visible:ring-yellow-400", Info = "focus-visible:ring-blue-500 dark:focus-visible:ring-blue-400", Light = "focus-visible:ring-gray-400 dark:focus-visible:ring-gray-300", Dark = "focus-visible:ring-gray-700 dark:focus-visible:ring-gray-300" }, PeerFocusRingBase = "peer-focus-visible:ring-2 peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-[oklch(100%_0_0)] dark:peer-focus-visible:ring-offset-[oklch(25.33%_0.016_252.42)] forced-colors:peer-focus-visible:outline-2 forced-colors:peer-focus-visible:outline-offset-2 forced-colors:peer-focus-visible:outline-[Highlight]", PeerFocusColors = new() { Primary = "peer-focus-visible:ring-purple-500 dark:peer-focus-visible:ring-purple-400", Accent = "peer-focus-visible:ring-fuchsia-500 dark:peer-focus-visible:ring-fuchsia-400", Success = "peer-focus-visible:ring-green-600 dark:peer-focus-visible:ring-green-400", Danger = "peer-focus-visible:ring-red-500 dark:peer-focus-visible:ring-red-400", Warning = "peer-focus-visible:ring-yellow-500 dark:peer-focus-visible:ring-yellow-400", Info = "peer-focus-visible:ring-blue-500 dark:peer-focus-visible:ring-blue-400", Light = "peer-focus-visible:ring-gray-400 dark:peer-focus-visible:ring-gray-300", Dark = "peer-focus-visible:ring-gray-700 dark:peer-focus-visible:ring-gray-300" }, SurfaceColors = new() { Filled = new() { Primary = $"{background.Medium.Primary} hover:bg-purple-700 active:bg-purple-800 {text.Medium.Light}", Accent = "bg-fuchsia-700 hover:bg-fuchsia-800 active:bg-fuchsia-900 text-gray-100", Success = $"{background.Medium.Success} hover:bg-green-700 active:bg-green-800 text-white", Danger = "bg-red-700 hover:bg-red-800 active:bg-red-900 text-gray-100", Warning = $"{background.Medium.Warning} hover:bg-yellow-600 active:bg-yellow-700 {text.Medium.Dark}", Info = $"{background.Medium.Info} hover:bg-blue-700 active:bg-blue-800 {text.Medium.Light}", Light = $"{background.Medium.Light} hover:bg-gray-50 active:bg-gray-100 {text.Medium.Dark}", Dark = $"{background.Dark.Dark} hover:bg-gray-800 active:bg-gray-700 {text.Medium.Light}", }, Outlined = new() { Primary = $"{text.Medium.Primary} {darkText.Light.Primary} {transparentBackground} {hoverColors.Primary} {borderWidth.Medium} {borderColors.Primary}", Accent = $"{text.Medium.Accent} {darkText.Light.Accent} {transparentBackground} {hoverColors.Accent} {borderWidth.Medium} {borderColors.Accent}", Success = $"{text.Medium.Success} {darkText.Light.Success} {transparentBackground} {hoverColors.Success} {borderWidth.Medium} {borderColors.Success}", Danger = $"{text.Medium.Danger} {darkText.Light.Danger} {transparentBackground} {hoverColors.Danger} {borderWidth.Medium} {borderColors.Danger}", Warning = $"{text.Medium.Warning} {darkText.Light.Warning} {transparentBackground} {hoverColors.Warning} {borderWidth.Medium} {borderColors.Warning}", Info = $"{text.Medium.Info} {darkText.Light.Info} {transparentBackground} {hoverColors.Info} {borderWidth.Medium} {borderColors.Info}", Light = $"{text.Light.Dark} {transparentBackground} {hoverColors.Light} {borderWidth.Medium} {borderColors.Light}", Dark = $"{text.Medium.Dark} {darkText.Light.Dark} {transparentBackground} {hoverColors.Dark} {borderWidth.Medium} {neutralSurface.BorderStrong}", }, Text = new() { Primary = $"{text.Medium.Primary} {darkText.Light.Primary} {transparentBackground} {hoverColors.Primary}", Accent = $"{text.Medium.Accent} {darkText.Light.Accent} {transparentBackground} {hoverColors.Accent}", Success = $"{text.Medium.Success} {darkText.Light.Success} {transparentBackground} {hoverColors.Success}", Danger = $"{text.Medium.Danger} {darkText.Light.Danger} {transparentBackground} {hoverColors.Danger}", Warning = $"{text.Medium.Warning} {darkText.Light.Warning} {transparentBackground} {hoverColors.Warning}", Info = $"{text.Medium.Info} {darkText.Light.Info} {transparentBackground} {hoverColors.Info}", Light = $"{text.Light.Dark} {transparentBackground} {hoverColors.Light}", Dark = $"{text.Dark.Dark} {darkText.Light.Dark} {transparentBackground} {hoverColors.Dark}", }, }, NeutralSurface = neutralSurface, NeutralText = neutralText }, Shadows = shadows, Rounded = rounded, Components = [ overlayTheme, new TwAlertTheme { Colors = new() { Primary = $"{background.Light.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} {borderWidth.AccentEdge} {borderColors.Primary}", Accent = $"{background.Light.Accent} {darkBackground.Dark.Accent} {text.Dark.Accent} {darkText.Light.Accent} {borderWidth.AccentEdge} {borderColors.Accent}", Success = $"{background.Light.Success} {darkBackground.Dark.Success} {text.Dark.Success} {darkText.Light.Success} {borderWidth.AccentEdge} {borderColors.Success}", Danger = $"{background.Light.Danger} {darkBackground.Dark.Danger} {text.Dark.Danger} {darkText.Light.Danger} {borderWidth.AccentEdge} {borderColors.Danger}", Warning = $"{background.Light.Warning} {darkBackground.Dark.Warning} {text.Dark.Warning} {darkText.Light.Warning} {borderWidth.AccentEdge} {borderColors.Warning}", Info = $"{background.Light.Info} {darkBackground.Dark.Info} {text.Dark.Info} {darkText.Light.Info} {borderWidth.AccentEdge} {borderColors.Info}", Light = $"{background.Light.Light} {darkBackground.Dark.Light} {text.Medium.Dark} {darkText.Medium.Dark} {borderWidth.AccentEdge} {borderColors.Light}", Dark = $"{background.Light.Dark} {darkBackground.Dark.Dark} {text.Medium.Dark} {darkText.Light.Dark} {borderWidth.AccentEdge} {borderColors.Dark}", }, TextWrapper = $"{flexbox.Flex1} {sizing.MinWidthNone} {typography.WrapBreakWord}", Padding = "py-4 px-6", DensePadding = "py-2 px-3", StartIconPadding = "pe-2", EndIconPadding = "ps-2", Transition = transition.ColorsSlow, DismissButtonSize = $"{sizing.Icon.Xl} {display.Flex} {anchor.Center} {rounded.Full}", DismissButtonSpacingWithEndIcon = "ms-2", DismissButtonColor = $"text-current {neutralHoverFill} opacity-70 hover:opacity-100 focus-visible:ring-2 focus-visible:ring-current transition-[opacity,background-color] {transition.DurationFast} motion-reduce:transition-none {interaction.FocusOutlineNone}" }, new TwAvatarTheme { Colors = new() { Primary = $"{background.Medium.Primary} {text.Medium.Light}", Accent = "bg-fuchsia-700 text-gray-100", Success = $"{background.Medium.Success} text-white", Danger = "bg-red-700 text-gray-100", Warning = $"{background.Medium.Warning} {text.Medium.Dark}", Info = $"{background.Medium.Info} {text.Medium.Light}", Light = $"{background.Medium.Light} {text.Medium.Dark}", Dark = $"{background.Dark.Dark} {text.Medium.Light}", }, Neutral = $"{neutralTrack} {neutralText.Secondary}", Base = $"{display.InlineFlex} {anchor.Center} {flexbox.ShrinkNone} {overflow.Hidden} {typography.Weight.Semibold} leading-none select-none", Small = $"size-8 {typography.Size.Xs}", Medium = $"size-10 {typography.Size.Sm}", Large = $"size-12 {typography.Size.Base}", ExtraLarge = "size-16 text-xl", Image = $"{sizing.Full} object-cover", Icon = "text-[1.25em]" }, new TwBreadcrumbTheme { List = $"{display.InlineFlex} {flexbox.Wrap} {flexbox.Align.Center} {spacing.Gap.Sm} {typography.Size.Sm}", Item = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Sm} {sizing.MinWidthNone}", Separator = $"{display.InlineFlex} {flexbox.Align.Center} {neutralText.Subtle} select-none", SeparatorIcon = "text-[0.875em] leading-none", Label = $"{display.InlineFlex} {flexbox.Align.Center} gap-1.5 px-1.5 py-1 {rounded.Md} {typography.WrapBreakWord}", Link = $"{typography.Weight.Medium} {neutralText.Muted} hover:text-purple-700 dark:hover:text-purple-300 hover:bg-purple-50 dark:hover:bg-purple-500/15 {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", Current = $"{typography.Weight.Semibold} {neutralText.Heading}", Icon = $"{flexbox.ShrinkNone} leading-none", CurrentIcon = "text-purple-600 dark:text-purple-400" }, new TwButtonTheme { Base = $"{display.InlineFlex} {overflow.Hidden} {anchor.Center} min-h-8 {typography.Size.Sm} {typography.AlignCenter} {transition.ColorsFast} {interaction.FocusOutlineNone} focus-visible:outline-hidden touch-manipulation", Padding = "px-6 py-1", DensePadding = "px-3 py-1", IconButton = $"{display.InlineFlex} {anchor.Center} {sizing.Icon.Xl} {typography.Size.Sm} {rounded.Full} {interaction.FocusOutlineNone}", Typography = typography.Weight.Medium, IconTypography = $"{typography.Size.Lg} leading-none", Uppercase = $"{textTransform.Uppercase} tracking-wide", DisabledCursor = interaction.DisabledCursor, ReadonlyCursor = interaction.ReadonlyCursor, DefaultCursor = interaction.PointerCursor, DisabledFilled = $"bg-[oklch(21%_0.006_285.885)]/15 dark:bg-[oklch(97.807%_0.029_256.847)]/15 {disabledInk} shadow-none {interaction.DisabledCursor}", DisabledOutlined = $"{disabledInk} {transparentBackground} {borderWidth.Thin} border-[oklch(21%_0.006_285.885)]/15 dark:border-[oklch(97.807%_0.029_256.847)]/15 {interaction.DisabledCursor}", DisabledText = $"{disabledInk} {transparentBackground} {interaction.DisabledCursor}" }, new TwCardTheme { Container = "px-6 py-5", Bordered = $"{borderWidth.Thin} {neutralSurface.Border}", Title = $"{typography.Size.Lg} {typography.Weight.Semibold} {typography.WrapBreakWord} {neutralText.Heading}" }, new TwCarouselTheme { Container = $"{positioning.Relative} {overflow.Hidden} {sizing.FullWidth}", Viewport = $"{positioning.Relative} {sizing.Full}", Slide = sizing.Full, SlideContent = sizing.Full, ArrowButton = $"{positioning.Absolute} top-1/2 -translate-y-1/2 z-10 text-lg {shadows.Md}", ArrowButtonStart = "start-2", ArrowButtonEnd = "end-2", PlayPauseButton = $"{positioning.Absolute} top-2 end-2 z-10 text-sm {shadows.Md}", IndicatorContainer = $"{positioning.Absolute} bottom-2 inset-x-0 z-10 w-fit mx-auto {display.Flex} {flexbox.Justify.Center} {flexbox.Align.Center} gap-4 px-4 py-2 {rounded.Full} bg-white/45 dark:bg-black/60 {shadows.Md}", Indicator = $"{positioning.Relative} size-2.5 before:absolute before:-inset-2 before:content-[''] {rounded.Full} {interaction.PointerCursor} {interaction.FocusOutlineNone} {focusRing} focus-visible:ring-offset-2 focus-visible:ring-offset-[oklch(100%_0_0)] dark:focus-visible:ring-offset-[oklch(25.33%_0.016_252.42)] forced-colors:border forced-colors:border-[ButtonText] {transition.ColorsFast}", IndicatorActive = "bg-purple-600 dark:bg-purple-500 forced-colors:bg-[Highlight]", IndicatorInactive = "bg-[oklch(21%_0.006_285.885)]/45 dark:bg-[oklch(97.807%_0.029_256.847)]/50 hover:bg-[oklch(21%_0.006_285.885)]/65 dark:hover:bg-[oklch(97.807%_0.029_256.847)]/70" }, new TwCheckboxTheme { Colors = checkBoxRadioButtonColors, Base = $"peer {borderWidth.Thick} {neutralSurface.BorderStrong} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast} {transition.EaseInOut} {interaction.PointerCursor} appearance-none", Disabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", Hover = $"hover:border-[oklch(21%_0.006_285.885)]/40 dark:hover:border-[oklch(97.807%_0.029_256.847)]/40 {interaction.PointerCursor}", LabelBase = $"{display.Flex} {positioning.Relative} {flexbox.Align.Center} {spacing.Gap.Md} min-h-[24px] {inputLabelText} select-none", LabelInteractiveCursor = interaction.PointerCursor, LabelNonInteractiveCursor = interaction.PointerEventsNone, LabelDisabled = interaction.DisabledOpacity, IconWrapper = $"{positioning.Absolute} opacity-0 peer-checked:opacity-100 translate-x-1/4 rtl:-translate-x-1/4", IndeterminateIconWrapper = $"{positioning.Absolute} translate-x-1/4 rtl:-translate-x-1/4" }, new TwChartTheme { Container = $"{display.Flex} {flexbox.Col} {spacing.Gap.Lg} {sizing.FullWidth} {sizing.MinWidthNone} m-0", Header = $"{display.Flex} {flexbox.Col} gap-0.5", Title = $"{typography.Size.Base} {typography.Weight.Semibold} {neutralText.Heading}", Description = $"{typography.Size.Sm} {neutralText.Muted}", Body = $"{sizing.FullWidth} {sizing.MinWidthNone}", Chart = $"{display.Flex} {flexbox.Col} {spacing.Gap.Lg} {sizing.FullWidth} {sizing.MinWidthNone}", Toolbar = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} gap-x-4 gap-y-2", Legend = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} gap-x-4 gap-y-1 list-none m-0 p-0", LegendItem = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} {typography.Size.Xs} {neutralText.Secondary}", LegendButton = $"{rounded.Sm} {interaction.PointerCursor} {interaction.FocusOutlineNone} {focusRing} {neutralHoverText} {transition.ColorsFast}", LegendItemHidden = "opacity-50 line-through", LegendSwatch = $"size-2.5 {rounded.Sm} {flexbox.ShrinkNone}", TableToggle = spacing.PushEnd, AxisTitle = $"{typography.Size.Xs} {neutralText.Muted}", XAxisTitle = typography.AlignCenter, Frame = sizing.FullWidth, FrameWithYAxis = $"{display.Grid} grid-cols-[auto_minmax(0,1fr)] {sizing.FullWidth}", YAxis = $"{positioning.Relative} max-w-32 pe-2", AxisSizer = $"{display.Flex} {flexbox.Col} h-0 {overflow.Hidden} invisible", Tick = $"{typography.Size.Xs} leading-none tabular-nums whitespace-nowrap {neutralText.Muted}", YTick = $"{positioning.Absolute} end-2 max-w-full truncate", XAxis = $"{positioning.Relative} h-6", XTick = $"{positioning.Absolute} top-2 truncate", Plot = $"{positioning.Relative} {sizing.FullWidth}", Small = "h-40", Medium = "h-64", Large = "h-96", Square = "aspect-square mx-auto", SquareSmall = "max-w-48", SquareMedium = "max-w-72", SquareLarge = "max-w-md", Canvas = $"{positioning.Absolute} inset-0 {sizing.Full} overflow-visible", Rect = $"{positioning.Absolute} forced-color-adjust-none", RoundedTop = "rounded-t-sm", RoundedBottom = "rounded-b-sm", RoundedLeft = "rounded-l-sm", RoundedRight = "rounded-r-sm", RoundedAll = rounded.Sm, SurfaceRing = "ring-1 ring-[oklch(100%_0_0)] dark:ring-[oklch(25.33%_0.016_252.42)]", Dot = $"{positioning.Absolute} {rounded.Full} ring-2 ring-[oklch(100%_0_0)] dark:ring-[oklch(25.33%_0.016_252.42)] forced-color-adjust-none", Glyph = $"{positioning.Absolute} {display.Flex} leading-none", Text = $"{positioning.Absolute} {typography.Size.Xs} leading-none tabular-nums whitespace-nowrap", TextMuted = neutralText.Muted, TextPrimary = neutralText.Heading, TextInverse = "text-white", TextStrong = typography.Weight.Semibold, TextLarge = "text-3xl", TextTruncate = "truncate", FillNone = "fill-none", StrokeHairline = "stroke-1", StrokeNormal = "stroke-2", StrokeThick = "stroke-[6px]", SurfaceStroke = "stroke-2 stroke-[oklch(100%_0_0)] dark:stroke-[oklch(25.33%_0.016_252.42)]", HitWrapper = "min-w-6 min-h-6 hover:z-10 focus-within:z-10", HitWrapperShaped = interaction.PointerEventsNone, HitShape = $"{positioning.Absolute} inset-0 pointer-events-auto", Hit = $"{positioning.Absolute} inset-0 {rounded.Sm} {interaction.FocusOutlineNone} {focusRing} dark:focus-visible:ring-offset-2 dark:focus-visible:ring-offset-[oklch(97.807%_0.029_256.847)]", HitHighlight = $"{positioning.Absolute} inset-0 {rounded.Sm} bg-[oklch(21%_0.006_285.885)]/8 dark:bg-[oklch(97.807%_0.029_256.847)]/10 invisible group-hover:visible group-has-[:focus-visible]:visible group-data-[tw-tooltip-open]:visible {interaction.PointerEventsNone}", Crosshair = $"{positioning.Absolute} inset-y-0 left-1/2 w-px bg-[oklch(21%_0.006_285.885)]/40 dark:bg-[oklch(97.807%_0.029_256.847)]/40 invisible group-hover:visible group-has-[:focus-visible]:visible group-data-[tw-tooltip-open]:visible {interaction.PointerEventsNone}", TooltipTitle = $"{display.Block} {typography.Weight.Semibold}", TooltipRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} mt-1 font-normal", TooltipKey = $"h-0.5 w-3 {rounded.Full} {flexbox.ShrinkNone}", TooltipLabel = neutralText.Secondary, TooltipValue = $"{spacing.PushEnd} ps-3 {typography.Weight.Semibold} tabular-nums", Empty = $"py-8 {typography.AlignCenter} {typography.Size.Sm} {neutralText.Muted}", TableRowHeader = typography.Weight.Medium, Series = [ new() { Background = "bg-purple-600 dark:bg-purple-500", Fill = "fill-purple-600 dark:fill-purple-500", Stroke = "stroke-purple-600 dark:stroke-purple-500", Text = "text-purple-600 dark:text-purple-500" }, new() { Background = "bg-orange-600", Fill = "fill-orange-600", Stroke = "stroke-orange-600", Text = "text-orange-600" }, new() { Background = "bg-teal-600", Fill = "fill-teal-600", Stroke = "stroke-teal-600", Text = "text-teal-600" }, new() { Background = "bg-yellow-700", Fill = "fill-yellow-700", Stroke = "stroke-yellow-700", Text = "text-yellow-700" }, new() { Background = "bg-pink-500", Fill = "fill-pink-500", Stroke = "stroke-pink-500", Text = "text-pink-500" }, new() { Background = "bg-green-600", Fill = "fill-green-600", Stroke = "stroke-green-600", Text = "text-green-600" }, new() { Background = "bg-blue-600 dark:bg-blue-500", Fill = "fill-blue-600 dark:fill-blue-500", Stroke = "stroke-blue-600 dark:stroke-blue-500", Text = "text-blue-600 dark:text-blue-500" }, new() { Background = "bg-red-600 dark:bg-red-500", Fill = "fill-red-600 dark:fill-red-500", Stroke = "stroke-red-600 dark:stroke-red-500", Text = "text-red-600 dark:text-red-500" } ], Positive = new() { Background = "bg-green-600", Fill = "fill-green-600", Stroke = "stroke-green-600", Text = "text-green-600" }, Negative = new() { Background = "bg-red-600 dark:bg-red-500", Fill = "fill-red-600 dark:fill-red-500", Stroke = "stroke-red-600 dark:stroke-red-500", Text = "text-red-600 dark:text-red-500" }, Total = new() { Background = "bg-slate-500 dark:bg-slate-400", Fill = "fill-slate-500 dark:fill-slate-400", Stroke = "stroke-slate-500 dark:stroke-slate-400", Text = "text-slate-500 dark:text-slate-400" }, Sequential = new() { Background = "bg-purple-600 dark:bg-purple-500", Fill = "fill-purple-600 dark:fill-purple-500", Stroke = "stroke-purple-600 dark:stroke-purple-500", Text = "text-purple-600 dark:text-purple-500" }, Track = new() { Background = "bg-[oklch(91%_0_0)] dark:bg-[oklch(34%_0.016_253)]", Fill = "fill-[oklch(91%_0_0)] dark:fill-[oklch(34%_0.016_253)]", Stroke = "stroke-[oklch(91%_0_0)] dark:stroke-[oklch(34%_0.016_253)]", Text = "text-[oklch(91%_0_0)] dark:text-[oklch(34%_0.016_253)]" }, Grid = new() { Background = "bg-[oklch(92%_0_0)] dark:bg-[oklch(32%_0.016_253)]", Fill = "fill-[oklch(92%_0_0)] dark:fill-[oklch(32%_0.016_253)]", Stroke = "stroke-[oklch(92%_0_0)] dark:stroke-[oklch(32%_0.016_253)]", Text = "text-[oklch(92%_0_0)] dark:text-[oklch(32%_0.016_253)]" }, Axis = new() { Background = "bg-[oklch(78%_0_0)] dark:bg-[oklch(48%_0.016_253)]", Fill = "fill-[oklch(78%_0_0)] dark:fill-[oklch(48%_0.016_253)]", Stroke = "stroke-[oklch(78%_0_0)] dark:stroke-[oklch(48%_0.016_253)]", Text = "text-[oklch(78%_0_0)] dark:text-[oklch(48%_0.016_253)]" }, Ink = new() { Background = "bg-[oklch(21%_0.006_285.885)] dark:bg-[oklch(97.807%_0.029_256.847)]", Fill = "fill-[oklch(21%_0.006_285.885)] dark:fill-[oklch(97.807%_0.029_256.847)]", Stroke = "stroke-[oklch(21%_0.006_285.885)] dark:stroke-[oklch(97.807%_0.029_256.847)]", Text = neutralText.Heading } }, new TwChipTheme { Base = $"{display.InlineFlex} {anchor.Center} gap-1.5 {typography.Weight.Medium} {shadows.Sm} {transition.ColorsFast} touch-manipulation", CloseButton = $"{display.Flex} {anchor.Center} {sizing.Icon.Sm} {typography.AlignCenter} {neutralHoverFill} {rounded.Full} {transition.ColorsFast}", ContentButton = $"{display.InlineFlex} {anchor.Center} gap-1.5 bg-transparent text-inherit {rounded.Full} {interaction.PointerCursor} {interaction.FocusOutlineNone} focus-visible:ring-2 focus-visible:ring-current", Sm = "h-5 px-1.5 py-1 text-[10px] leading-none", Md = $"h-6 px-2 py-1 {typography.Size.Xs} leading-none", Lg = $"h-8 px-2.5 py-1.5 {typography.Size.Sm} leading-none" }, new TwCodeBlockTheme { Container = $"{overflow.Hidden} p-1 {neutralSurface.BackgroundSubtle} {borderWidth.Thin} {neutralSurface.Border}", Header = $"px-2 py-1 {typography.Size.Xs} {typography.Weight.Medium} {textTransform.Uppercase} tracking-wide {neutralText.Muted}", Panel = $"{rounded.Md} {typography.Size.Sm} {neutralSurface.Background} {neutralText.Heading} {borderWidth.Thin} {neutralSurface.Border}", Code = $"{rounded.Md} {focusRingInset} {interaction.FocusOutlineNone}", CopyButtonWrapper = $"{neutralText.Muted} {neutralHoverText} {transition.ColorsFast}" }, new TwCollapseTheme { Container = $"tw-collapse {borderWidth.Thin} {neutralSurface.Border}", Trigger = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Md} {sizing.FullWidth} {spacing.InteractiveRowPadding} text-start {typography.Weight.Medium} {neutralText.Heading} {neutralSurface.Hover} {focusRingInset} {transition.ColorsFast} {interaction.FocusOutlineNone} touch-manipulation", Icon = $"{display.Flex} {flexbox.ShrinkNone} {sizing.Icon.Sm} {spacing.PushEnd} {transition.TransformSlow}", IconOpen = "rotate-180", Content = $"{overflow.Hidden} border-t {neutralSurface.Border} {transition.ColorsSlow}" }, new TwColorPickerTheme { Swatch = $"block {flexbox.ShrinkNone} h-7 w-7 {neutralHairlineRing} {shadows.Sm} transition-[box-shadow,opacity] {transition.DurationFast} motion-reduce:transition-none", SwatchDisabled = interaction.DisabledOpacity, SwatchHover = "hover:ring-[oklch(21%_0.006_285.885)]/20 dark:hover:ring-[oklch(97.807%_0.029_256.847)]/25", InputContainer = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md}", DialogPosition = $"{positioning.Fixed} z-120 {spacing.MarginTop.Md}", PreviewSwatch =$"{flexbox.Flex1} {sizing.MinWidthNone} h-6 {rounded.Full} {neutralHairlineRing} {shadows.Sm}", SelectorSquare = $"{positioning.Relative} {overflow.Hidden} {sizing.FullWidth} h-48 {neutralHairlineRing} {focusRing} {interaction.FocusOutlineNone} cursor-crosshair touch-none", SelectorThumb = $"{positioning.Absolute} {sizing.Icon.Sm} {rounded.Full} border-2 border-white ring-1 ring-black/10 {shadows.Lg} {interaction.PointerEventsNone}", SliderTrack = $"{overflow.Hidden} {sizing.FullWidth} h-2.5 {rounded.Full} {neutralHairlineRing} {interaction.PointerEventsNone}", SliderThumb = $"{positioning.Absolute} top-1/2 {sizing.Icon.Sm} {rounded.Full} border-2 border-white ring-1 ring-black/10 {shadows.Lg} {interaction.PointerEventsNone}", AlphaLabel = $"{typography.Size.Xs} {typography.Weight.Medium} {neutralText.Secondary}", ActionBar = $"{display.Flex} {flexbox.Justify.End} {spacing.Gap.Md} pt-1", ControlRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {spacing.Padding.Md} {neutralSurface.BackgroundSubtle}", Body = $"{display.Flex} {flexbox.Col} {spacing.Gap.Lg}", SliderRow = $"{flexbox.Flex1} h-6 {rounded.Full} {focusRing} {interaction.FocusOutlineNone}", HueSliderTouch = "touch-none", InputColumn = flexbox.Flex1, ModeSwitchButton = "shrink-0 tracking-wide", AlphaReadoutAlign = "text-end" }, new TwDatePickerTheme { Header = $"{typography.AlignCenter} {typography.Weight.Medium} {overlayTheme.Popover.Background} {rounded.RoundedTop.Lg} border-b {neutralSurface.BorderStrong}", WeekdaysHeader = $"{display.Flex} {anchor.Center} h-8 {typography.Size.Xs} font-normal {neutralText.Muted}", Base = $"{positioning.Fixed} z-120 {flexbox.Row} md:flex-row {flexbox.Align.Center} mt-1 px-2 pb-2 {typography.AlignCenter} {typography.Size.Sm} {typography.Weight.Medium} {transition.ColorsFast} {interaction.PointerCursor}", ActiveClass = $"{neutralTrack} {neutralText.Heading} {typography.Weight.Semibold}", SelectedClass = $"bg-purple-600 hover:bg-purple-700 text-white {typography.Weight.Semibold}", HoverClass = neutralHoverFill, ButtonClass = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Center} h-8 {sizing.FullWidth} {spacing.Padding.Md} tabular-nums {focusRingInset} {interaction.FocusOutlineNone} {transition.ColorsFast}", RangeClass = "bg-purple-100 text-purple-900 dark:bg-purple-500/20 dark:text-purple-100", RangeMonthCaptionClass = $"mt-2 {typography.AlignCenter} {typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Heading}", PrevMonthClass = neutralText.Subtle, DefaultFormat = "dd/MM/yyyy", DefaultDateTimeFormat = "dd/MM/yyyy HH:mm", DefaultDateTimeFormat12Hour = "dd/MM/yyyy hh:mm tt", DefaultRangeSeparator = " - ", IconTriggerWrapper = $"{positioning.Absolute} {inset.Top} {inset.Start} {display.Flex} {flexbox.Align.Center} {spacing.PaddingStart.Lg} {interaction.PointerCursor}", IconGlyph = $"{sizing.Icon.Md} {neutralText.Subtle}", TextfieldPadding = "ps-10 pe-3", NativeInputAppearance = "appearance-none !flex items-center [&::-webkit-date-and-time-value]:min-h-0 [&::-webkit-date-and-time-value]:text-start [&::-webkit-datetime-edit]:p-0", PanelWidth = "w-67", HeaderControls = $"{display.Flex} {flexbox.Justify.Between} {flexbox.Align.Center} h-9", Body = display.Flex, YearsGrid = $"{display.Grid} grid-cols-5 justify-items-stretch {spacing.Gap.Sm} {sizing.FullWidth} {spacing.MarginTop.Md}", MonthsGrid = $"{display.Grid} grid-cols-6 justify-items-stretch {spacing.Gap.Sm} {sizing.FullWidth} {spacing.MarginTop.Md}", DualMonthLayout = $"{display.Flex} {flexbox.Col} md:flex-row {spacing.Gap.Xl}", DualMonthColumn = "md:flex-1 md:min-w-0", DayGrid = $"{sizing.FullWidth} border-collapse", DayHeaderCellPadding = "p-0", DayAbbreviation = "no-underline", RangeStageTabsContainer = $"{display.Flex} {spacing.Gap.Sm} {spacing.Padding.Sm} {rounded.Lg} {neutralTrack} {spacing.MarginBottom.Md}", RangeStageTabInactive = neutralText.Subtle, PanelMaxHeight = "overflow-y-auto max-h-[calc(100vh-2rem)]", PanelMaxWidth = "overflow-x-auto max-w-[calc(100vw-2rem)]", DualMonthPanelWidth = "md:w-138", StageTabBase = $"{flexbox.Flex1} py-1.5 {typography.Size.Sm} {typography.Weight.Medium} {typography.AlignCenter} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", StageTabActive = $"bg-white dark:bg-[oklch(34%_0.018_253)] {neutralText.Heading} {shadows.Sm}", HeaderNavButton = "py-2 px-4 text-xl" }, new TwFileUploadTheme { IconSpacing = "me-2", FileList = $"{typography.Size.Sm} {neutralText.Secondary}", ChipTextColor = "dark:text-white", FocusRing = "has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-purple-500 dark:has-[:focus-visible]:ring-purple-400 has-[:focus-visible]:ring-offset-2 has-[:focus-visible]:ring-offset-[oklch(100%_0_0)] dark:has-[:focus-visible]:ring-offset-[oklch(25.33%_0.016_252.42)] forced-colors:has-[:focus-visible]:outline-2 forced-colors:has-[:focus-visible]:outline-offset-2 forced-colors:has-[:focus-visible]:outline-[Highlight]" }, new TwFooterTheme { Footer = $"{sizing.FullWidth} {neutralSurface.BackgroundSubtle} {neutralText.Secondary} border-t {neutralSurface.Border}", Container = "mx-auto w-full max-w-7xl px-6 py-10", Brand = "mb-8", Sections = $"{display.Grid} grid-cols-2 gap-8 md:grid-cols-4", Section = sizing.MinWidthNone, SectionTitle = $"{typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Heading}", LinkList = $"mt-3 {display.Flex} {flexbox.Col} {spacing.Gap.Md} list-none m-0 p-0", Link = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} {typography.Size.Sm} {rounded.Sm} underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current", Content = "mt-8 first:mt-0", Bottom = $"mt-8 {display.Flex} {flexbox.Wrap} {flexbox.Align.Center} {flexbox.Justify.Between} gap-x-6 gap-y-3 border-t border-current/15 pt-6 first:mt-0 first:border-t-0 first:pt-0 {typography.Size.Xs}", Copyright = "m-0 max-w-3xl", BottomLinks = $"{display.Flex} {flexbox.Wrap} gap-x-4 gap-y-2 list-none m-0 p-0" }, new TwIconTheme { Colors = new() { Primary = "text-purple-600 dark:text-purple-400", Accent = "text-fuchsia-600 dark:text-fuchsia-400", Success = "text-green-600 dark:text-green-400", Danger = "text-red-600 dark:text-red-400", Warning = "text-[oklch(65%_0.15_80)] dark:text-yellow-400", Info = "text-blue-600 dark:text-blue-400", Light = "text-gray-100 dark:text-white", Dark = "text-gray-950 dark:text-gray-950", }, HoverBackground = "hover:bg-current/10 dark:hover:bg-current/15", Pulse = "relative tw-icon-pulse" }, new TwLinkTheme { Default = $"underline-offset-2 hover:underline {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}" }, new TwGroupsTheme { Gap = spacing.Gap.Md, FieldsetBase = "p-0 m-0 border-none", HorizontalLayout = $"{display.Flex} {flexbox.Row} {flexbox.Wrap}", VerticalLayout = $"{display.Flex} {flexbox.Col}", CheckboxGroupDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", RadioGroupDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", ButtonGroupBase = display.InlineFlex, ButtonGroupVertical = flexbox.Col, ButtonGroupHorizontal = $"{flexbox.Row} {flexbox.Wrap}", ButtonGroupFullWidth = sizing.FullWidth, ButtonGroupFullWidthRow = "[&>*]:flex-1", ChipGroupBase = $"{display.Flex} {flexbox.Wrap}", ChipGroupAlignStart = flexbox.Justify.Start, ChipGroupAlignCenter = flexbox.Justify.Center, ChipGroupAlignEnd = flexbox.Justify.End }, new TwInputTheme { DefaultInputVariant = InputVariant.Outlined, TextfieldBase = $"{display.Block} {sizing.FullWidth} {sizing.MinWidthNone} max-w-full {neutralText.Heading} placeholder:text-[oklch(21%_0.006_285.885)]/65 dark:placeholder:text-[oklch(97.807%_0.029_256.847)]/65 {transition.ColorsFast} {transition.EaseInOut} {interaction.FocusOutlineNone}", SelectBase = $"{display.Block} {sizing.FullWidth} pe-10 {neutralText.Heading} bg-[url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2020%2020%22%3E%3Cpath%20stroke%3D%22%236b7280%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%221.5%22%20d%3D%22m6%208%204%204%204-4%22%2F%3E%3C%2Fsvg%3E')] bg-[length:1.5em_1.5em] bg-[right_0.5rem_center] rtl:bg-[left_0.5rem_center] bg-no-repeat {transition.ColorsFast} appearance-none {interaction.FocusOutlineNone} supports-[appearance:base-select]:[appearance:base-select] supports-[appearance:base-select]:flex supports-[appearance:base-select]:items-center [&::picker(select)]:[appearance:base-select] [&::picker-icon]:hidden [&::picker(select)]:border-[oklch(21%_0.006_285.885)]/25 dark:[&::picker(select)]:border-[oklch(97.807%_0.029_256.847)]/20 [&::picker(select)]:bg-[oklch(100%_0_0)] dark:[&::picker(select)]:bg-[oklch(40%_0.016_253)]", Size = $"{inputHeight} {typography.Size.Base}", DenseSize = $"{inputDenseHeight} {typography.Size.Sm}", MultilineSize = $"[--textarea-py:0.75rem] py-(--textarea-py) {typography.Size.Base}", MultilineDenseSize = $"[--textarea-py:0.5rem] py-(--textarea-py) {typography.Size.Sm}", MultilineResize = "resize-y", MultilineAutoGrow = "field-sizing-content resize-none", FieldWrapper = positioning.Relative, FieldStartContent = $"{positioning.Absolute} top-0 start-0 {display.Flex} {flexbox.Align.Center} {interaction.PointerEventsNone}", FieldEndContent = $"{positioning.Absolute} top-0 end-0 {display.Flex} {flexbox.Align.Stretch} gap-1 py-px pe-px", ClearablePadding = "pe-10", ClearButton = $"{display.InlineFlex} w-8 {flexbox.Align.Center} {flexbox.Justify.Center} {flexbox.ShrinkNone} {rounded.Md} {neutralText.Secondary} {neutralHoverText} {neutralHoverFill} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone} disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent forced-colors:text-[ButtonText] forced-colors:disabled:text-[GrayText]", ClearButtonIcon = $"{typography.Size.Sm} leading-none", SelectOption = $"{spacing.Padding.Lg} dark:bg-gray-800 dark:text-white supports-[appearance:base-select]:[padding-inline:revert] supports-[appearance:base-select]:py-2 supports-[appearance:base-select]:bg-transparent dark:supports-[appearance:base-select]:bg-transparent supports-[appearance:base-select]:hover:bg-[oklch(97%_0_0)] dark:supports-[appearance:base-select]:hover:bg-[oklch(34%_0.018_253)] supports-[appearance:base-select]:checked:bg-purple-50 supports-[appearance:base-select]:checked:text-purple-700 dark:supports-[appearance:base-select]:checked:bg-purple-500/20 dark:supports-[appearance:base-select]:checked:text-purple-300", SelectNativeBackground = "!bg-white dark:!bg-gray-800", SelectDefaultPadding = "px-3", SelectReadOnlyBackground = "!bg-none", SelectMultiTriggerLayout = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} {spacing.Gap.Sm} min-h-10 py-0.5 {typography.Size.Base}", SelectNativeMultiOverlay = $"{positioning.Absolute} inset-0 {sizing.Full} m-0 opacity-0 {interaction.PointerCursor} {interaction.FocusOutlineNone} touch-manipulation", SelectMultiOpenButton = $"{flexbox.Flex1} min-w-[2rem] min-h-8 truncate text-start bg-transparent border-0 {interaction.FocusOutlineNone}", SelectPanelPosition = $"{positioning.Fixed} z-120 {spacing.MarginTop.Md}", SelectPanelSurface = $"overflow-y-auto max-h-64 {spacing.Padding.Sm}", SelectPanelItemText = "[&_label]:!text-[oklch(21%_0.006_285.885)] dark:[&_label]:!text-[oklch(97.807%_0.029_256.847)] [&_fieldset]:gap-0 [&_label]:w-full [&_label]:gap-2 [&_label]:px-2 [&_label]:py-2 [&_label]:text-base [&_input]:sr-only [&_label>span]:hidden [&_label::before]:content-['✓'] [&_label::before]:invisible [&_label::before]:w-4 [&_label::before]:shrink-0 [&_label::before]:text-center [&_label:has(input:checked)::before]:visible [&_label:hover]:bg-[oklch(97%_0_0)] dark:[&_label:hover]:bg-[oklch(34%_0.018_253)] [&_label:has(input:checked)]:bg-purple-50 dark:[&_label:has(input:checked)]:bg-purple-500/20 [&_label:has(input:checked)]:!text-purple-700 dark:[&_label:has(input:checked)]:!text-purple-300 [&_label:has(input:focus-visible)]:ring-2 [&_label:has(input:focus-visible)]:ring-inset [&_label:has(input:focus-visible)]:ring-purple-500 dark:[&_label:has(input:focus-visible)]:ring-purple-400", SelectCustomTrigger = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Md} {sizing.FullWidth} {sizing.MinWidthNone} text-start {neutralText.Heading} {transition.ColorsFast} {interaction.FocusOutlineNone} {interaction.PointerCursor}", SelectCustomPlaceholder = $"{neutralText.Muted}", SelectCustomChevron = $"{display.Flex} {anchor.Center} {sizing.Icon.Sm} {flexbox.ShrinkNone} leading-none {neutralText.Muted} {transition.TransformFast}", SelectCustomChevronOpen = "rotate-180", SelectCustomListbox = $"{display.Flex} {flexbox.Col} gap-0.5 {interaction.FocusOutlineNone}", SelectCustomOption = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Md} {rounded.Md} px-2 py-2 {typography.Size.Sm} {neutralText.Heading} {interaction.PointerCursor} select-none data-[active=true]:bg-[oklch(95%_0_0)] dark:data-[active=true]:bg-[oklch(48%_0.016_253)] data-[active=true]:outline-2 data-[active=true]:-outline-offset-2 data-[active=true]:outline-purple-600 dark:data-[active=true]:outline-purple-300 aria-selected:font-semibold", SelectMultiTriggerBase = $"{positioning.Relative} {sizing.FullWidth} {sizing.MinWidthNone} text-start pe-10 {neutralText.Heading} {transition.ColorsFast} {interaction.FocusOutlineNone} {interaction.PointerCursor}", SelectMultiChipsPadding = "ps-0.75", SelectMultiChevron = $"{positioning.Absolute} end-3 top-1/2 -translate-y-1/2 {display.Flex} {sizing.Icon.Sm} leading-none {neutralText.Muted} {transition.TransformFast} {interaction.PointerEventsNone}", SelectCustomCheck = $"{sizing.Icon.Sm} {flexbox.ShrinkNone} text-purple-600 dark:text-purple-300", InputLegendBase = $"mb-3 {typography.Size.Base} {typography.Weight.Medium} {neutralText.Secondary}", LabelBase = $"{display.Block} mb-2 {inputLabelText}", OutlinedBorder = $"{borderWidth.Thin} {neutralSurface.BorderStrong}", FilledBorder = $"border-b {neutralSurface.BorderStrong}", FocusBorder = "focus:border-purple-600 dark:focus:border-purple-400 focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-400", FocusVisibleBorder = "focus-visible:border-purple-600 dark:focus-visible:border-purple-400 focus-visible:ring-2 focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400", FocusWithinBorder = "has-[:focus-visible]:border-purple-600 dark:has-[:focus-visible]:border-purple-400 has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-purple-500 dark:has-[:focus-visible]:ring-purple-400", FilledBackgroundColor = neutralSurface.Elevated, ErrorMessage = $"{spacing.MarginTop.Sm} {typography.Size.Xs} {text.Medium.Danger} {darkText.Medium.Danger}" }, new TwNumericTheme { Adornment = $"self-center whitespace-nowrap select-none {neutralText.Secondary}", Button = $"{display.InlineFlex} {flexbox.Align.Center} {flexbox.Justify.Center} {flexbox.ShrinkNone} {rounded.Md} {neutralText.Secondary} {neutralHoverText} {neutralHoverFill} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone} disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent forced-colors:text-[ButtonText] forced-colors:disabled:text-[GrayText]", ButtonIcon = $"{typography.Size.Sm} leading-none" }, new TwMenuTheme { Root = $"{positioning.Relative} {display.InlineFlex}", Panel = $"z-50 min-w-48 max-w-xs overflow-y-auto {rounded.Lg} {borderWidth.Thin} {neutralSurface.Border} {neutralSurface.Background} shadow-lg py-1 {interaction.FocusOutlineNone}", Item = $"{display.Flex} {sizing.FullWidth} {flexbox.Align.Center} {spacing.Gap.Sm} px-3 py-2 text-start {typography.Size.Sm} {neutralText.Heading} {neutralRowHover} focus-visible:bg-[oklch(21%_0.006_285.885)]/5 dark:focus-visible:bg-[oklch(97.807%_0.029_256.847)]/8 {interaction.PointerCursor} {transition.ColorsFast} {interaction.FocusOutlineNone} {focusRingInset}", ItemDisabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", ItemIcon = $"{typography.Size.Base} {flexbox.ShrinkNone} {neutralText.Subtle}", CheckIcon = $"{typography.Size.Base} {flexbox.ShrinkNone} text-purple-600 dark:text-purple-300", CheckIconHidden = "invisible", Divider = $"my-1 border-t {neutralSurface.Border}", GroupLabel = $"px-3 pt-2 pb-1 {typography.Size.Xs} {typography.Weight.Semibold} {neutralText.Muted}" }, new TwOnThisPageTheme { Title = $"{spacing.MarginBottom.Lg} {typography.Weight.Semibold} {neutralText.Heading}", List = $"border-s {neutralSurface.Border}", Link = $"{display.Block} -ms-px py-1 ps-4 border-s border-transparent {neutralText.Muted} {neutralHoverText} hover:border-[oklch(21%_0.006_285.885)]/45 dark:hover:border-[oklch(97.807%_0.029_256.847)]/45 {transition.ColorsFast} {focusRingInset} {interaction.FocusOutlineNone}", LinkCurrent = $"aria-[current=location]:font-medium aria-[current=location]:border-purple-600 dark:aria-[current=location]:border-purple-400 aria-[current=location]:text-[oklch(21%_0.006_285.885)] dark:aria-[current=location]:text-[oklch(97.807%_0.029_256.847)] forced-colors:aria-[current=location]:border-[Highlight]" }, new TwPaginationTheme { List = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm}", Base = $"{display.Flex} {anchor.Center} tabular-nums select-none {transition.ColorsFast} {focusRingInset} {interaction.FocusOutlineNone}", Size = $"{inputHeight} min-w-10 px-3 {typography.Size.Sm}", DenseSize = $"{inputDenseHeight} min-w-8 px-2 {typography.Size.Sm}", ActiveButton = $"{typography.Weight.Semibold} bg-purple-50 text-purple-700 ring-1 ring-inset ring-purple-600/20 dark:bg-purple-500/20 dark:text-purple-300 dark:ring-purple-400/30 forced-colors:outline forced-colors:outline-2 forced-colors:-outline-offset-2 forced-colors:outline-[Highlight] {interaction.PointerCursor}", Buttons = $"{neutralText.Secondary} {neutralHoverFill} {neutralHoverText} {interaction.PointerCursor}", DisabledButton = "text-[oklch(21%_0.006_285.885)]/40 dark:text-[oklch(97.807%_0.029_256.847)]/40 cursor-not-allowed" }, new TwPickListTheme { Container = $"{display.Flex} {flexbox.Align.Start} {spacing.Gap.Lg}", Column = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm} {flexbox.Flex1} {sizing.MinWidthNone}", ColumnHeader = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Sm} min-h-8", Label = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Heading}", ReorderButtons = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm}", ReorderButton = $"{neutralText.Muted} {neutralHoverFill} {neutralHoverText} {transition.ColorsFast} aria-disabled:text-[oklch(21%_0.006_285.885)]/40 dark:aria-disabled:text-[oklch(97.807%_0.029_256.847)]/40 aria-disabled:hover:bg-transparent dark:aria-disabled:hover:bg-transparent aria-disabled:cursor-not-allowed", TransferButton = $"{borderWidth.Thin} {neutralSurface.BorderStrong} {neutralText.Secondary} {neutralHoverFill} {neutralHoverText} {transition.ColorsFast} aria-disabled:text-[oklch(21%_0.006_285.885)]/40 dark:aria-disabled:text-[oklch(97.807%_0.029_256.847)]/40 aria-disabled:border-[oklch(21%_0.006_285.885)]/20 dark:aria-disabled:border-[oklch(97.807%_0.029_256.847)]/20 aria-disabled:hover:bg-transparent dark:aria-disabled:hover:bg-transparent aria-disabled:cursor-not-allowed", TransferButtonColumn = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center} {flexbox.Justify.Center} {flexbox.AlignSelf.Center} {spacing.Gap.Md}", ListBox = $"overflow-y-auto {sizing.FullWidth} h-64 {spacing.Padding.Sm} {neutralSurface.Background} {borderWidth.Thin} {neutralSurface.BorderStrong}", ListBoxDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", Item = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {rounded.Md} px-3 py-2 {typography.Size.Sm} {neutralText.Heading} {neutralRowHover} aria-selected:bg-purple-50 aria-selected:text-purple-700 aria-selected:hover:bg-purple-100 dark:aria-selected:bg-purple-500/20 dark:aria-selected:text-purple-300 dark:aria-selected:hover:bg-purple-500/30 {focusRingInset} {transition.ColorsFast} {interaction.PointerCursor} select-none {interaction.FocusOutlineNone}", ItemSelected = typography.Weight.Medium, EmptyState = $"px-3 py-8 {typography.AlignCenter} {typography.Size.Sm} {neutralText.Subtle}" }, new TwProgressTheme { Colors = new() { Primary = "[&::-webkit-progress-value]:bg-purple-600 dark:[&::-webkit-progress-value]:bg-purple-500 [&::-moz-progress-bar]:bg-purple-600 dark:[&::-moz-progress-bar]:bg-purple-500", Accent = "[&::-webkit-progress-value]:bg-fuchsia-600 dark:[&::-webkit-progress-value]:bg-fuchsia-500 [&::-moz-progress-bar]:bg-fuchsia-600 dark:[&::-moz-progress-bar]:bg-fuchsia-500", Success = "[&::-webkit-progress-value]:bg-green-600 dark:[&::-webkit-progress-value]:bg-green-500 [&::-moz-progress-bar]:bg-green-600 dark:[&::-moz-progress-bar]:bg-green-500", Danger = "[&::-webkit-progress-value]:bg-red-600 dark:[&::-webkit-progress-value]:bg-red-500 [&::-moz-progress-bar]:bg-red-600 dark:[&::-moz-progress-bar]:bg-red-500", Warning = "[&::-webkit-progress-value]:bg-yellow-500 dark:[&::-webkit-progress-value]:bg-yellow-400 [&::-moz-progress-bar]:bg-yellow-500 dark:[&::-moz-progress-bar]:bg-yellow-400", Info = "[&::-webkit-progress-value]:bg-blue-600 dark:[&::-webkit-progress-value]:bg-blue-500 [&::-moz-progress-bar]:bg-blue-600 dark:[&::-moz-progress-bar]:bg-blue-500", Light = "[&::-webkit-progress-value]:bg-gray-400 dark:[&::-webkit-progress-value]:bg-gray-300 [&::-moz-progress-bar]:bg-gray-400 dark:[&::-moz-progress-bar]:bg-gray-300", Dark = "[&::-webkit-progress-value]:bg-gray-900 dark:[&::-webkit-progress-value]:bg-gray-100 [&::-moz-progress-bar]:bg-gray-900 dark:[&::-moz-progress-bar]:bg-gray-100" }, Base = $"{display.Block} {overflow.Hidden} {sizing.FullWidth} {sizing.MinWidthNone} tabular-nums {neutralTrackStrong} {rounded.Full} {borderWidth.Thin} {neutralSurface.BorderStrong} forced-colors:[&::-webkit-progress-value]:bg-[Highlight] forced-colors:[&::-moz-progress-bar]:bg-[Highlight] indeterminate:animate-pulse indeterminate:motion-reduce:animate-none appearance-none [&::-webkit-progress-bar]:rounded-full [&::-webkit-progress-bar]:bg-transparent [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:transition-[width] [&::-webkit-progress-value]:{transition.DurationSlow} [&::-moz-progress-bar]:rounded-full [&::-moz-progress-bar]:transition-[width] [&::-moz-progress-bar]:{transition.DurationSlow}", Small = "h-1.5", Medium = "h-2.5", Large = "h-4", Wrapper = $"{positioning.Relative} {display.Block}", Animated = $"{positioning.Absolute} inset-y-0 start-0 {overflow.Hidden} {rounded.Full} {interaction.PointerEventsNone} transition-[width] {transition.DurationSlow} tw-wave [--tw-wave-color:rgb(255_255_255/0.7)] dark:[--tw-wave-color:rgb(255_255_255/0.4)]" }, new TwTabTheme { TabBase = $"{positioning.Relative} {display.InlineFlex} {anchor.Center} {typography.Weight.Medium} {typography.Size.Sm} {transition.ColorsFast} {focusRingInset} {interaction.FocusOutlineNone} touch-manipulation", TabPadding = "px-6 py-3", TabDensePadding = "px-4 py-2", ActiveIndicator = "after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-current forced-colors:after:bg-[Highlight] after:scale-x-100 after:transition-transform after:duration-200 after:motion-reduce:transition-none", InactiveIndicator = $"{neutralText.Muted} {neutralHoverText} {neutralRowHover} after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-current after:scale-x-0 after:transition-transform after:duration-200 after:motion-reduce:transition-none", DisabledTab = $"{neutralText.Muted} {interaction.DisabledOpacity} {interaction.DisabledCursor}", TabListContainer = $"{display.Flex} {flexbox.Wrap} {overflow.Hidden} {borderWidth.Thin} {neutralSurface.Border}", PanelContainer = $"px-6 py-5 border-x border-b {neutralSurface.Border} {focusRingInset} {interaction.FocusOutlineNone}", Background = neutralSurface.Background, }, new TwBarcodeTheme { Base = $"{display.InlineFlex} {flexbox.Col} {flexbox.Align.Center} {flexbox.ShrinkNone} max-w-full forced-color-adjust-none", Background = "bg-white", Foreground = "text-black", Text = $"font-mono {typography.Size.Xs} tracking-widest pb-1", Small = "h-10 max-w-full", Medium = "h-16 max-w-full", Large = "h-24 max-w-full" }, new TwQrCodeTheme { Base = $"{display.InlineBlock} {flexbox.ShrinkNone} forced-color-adjust-none", Background = "bg-white dark:bg-transparent", Foreground = "text-black dark:text-white", Small = "size-24", Medium = "size-40", Large = "size-56", ExtraLarge = "size-72" }, new TwSkeletonTheme { Base = $"{display.Block} {positioning.Relative} {overflow.Hidden} {neutralTrack}", Text = $"{sizing.FullWidth} h-4", Circle = "size-12", Rectangle = $"{sizing.FullWidth} h-24", MeasuringWrapper = "invisible", Pulse = "animate-pulse motion-reduce:animate-none", Wave = "tw-wave" }, new TwSidebarTheme { SkipLink = "focus:not-sr-only focus:absolute focus:top-2 focus:start-2 focus:z-140 focus:px-3 focus:py-2 focus:text-sm focus:font-medium focus:bg-[oklch(100%_0_0)] dark:focus:bg-[oklch(40%_0.016_253)] focus:text-[oklch(21%_0.006_285.885)] dark:focus:text-[oklch(97.807%_0.029_256.847)] focus:rounded focus:shadow-lg", MobileOverlay = "inset-0 z-90 lg:hidden bg-black/50", DrawerCloseButton = "lg:hidden absolute top-2 end-2 text-lg", MobileClosed = "-translate-x-full rtl:translate-x-full", MobileOpen = "lg:relative translate-x-0", NavigationList = "overflow-y-auto pb-6", NavbarFixedInset = "left-0 right-0", NavbarNavigationResponsive = "lg:flex lg:flex-1 lg:flex-row lg:w-auto lg:p-0 lg:bg-transparent lg:shadow-none", NavbarNavigationExpanded = "flex flex-1", NavigationItemToggleLabel = "me-auto text-start", NavigationItemToggleIcon = "transition-transform", Navbar = $"{display.Flex} z-40 {flexbox.Align.Center} {flexbox.ShrinkNone} {sizing.FullWidth} min-h-14 px-4 py-2 {neutralSurface.Background} {neutralText.Heading} border-b {neutralSurface.Border}", NavbarContent = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} {spacing.Gap.Xl} {sizing.FullWidth}", NavbarBrand = flexbox.ShrinkNone, NavbarNavigation = $"{flexbox.Align.Center} {spacing.Gap.Md}", NavbarActions = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {spacing.PushEnd}", NavbarActionsCollapsible = "max-lg:ms-0 max-lg:mt-2 max-lg:flex-wrap max-lg:justify-center max-lg:border-t max-lg:border-current/15 max-lg:pt-3", NavbarToggle = $"lg:hidden {spacing.PushEnd} -me-2 size-11 {flexbox.ShrinkNone} text-2xl", NavbarToggleIcon = $"text-xl {neutralText.Secondary} {neutralHoverText} {transition.ColorsFast}", NavbarLink = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} px-3 py-1.5 {typography.Size.Sm} {typography.Weight.Medium} {neutralText.Secondary} {neutralHoverFill} {neutralHoverText} {rounded.Md} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", NavbarLinkCollapsible = "max-lg:w-full max-lg:min-h-11 max-lg:px-3 max-lg:text-base", NavbarLinkActive = $"{neutralTrack} {neutralText.Heading}", NavbarMobileMenu = "max-lg:basis-full max-lg:-mx-4 max-lg:-mt-2 max-lg:-mb-2 max-lg:max-h-[calc(100dvh-3.5rem)] max-lg:overflow-y-auto max-lg:overscroll-contain max-lg:items-stretch max-lg:gap-1 max-lg:border-t max-lg:border-current/15 max-lg:px-2 max-lg:py-2 max-lg:[&>a]:flex max-lg:[&>a]:min-h-11 max-lg:[&>a]:w-full max-lg:[&>a]:items-center max-lg:[&>a]:px-3 max-lg:[&>a]:text-base", Sidebar = $"z-100 overflow-auto scrollbar-gutter-stable overscroll-contain {flexbox.ShrinkNone} h-dvh w-64 {spacing.Padding.Xl} {neutralSurface.Background} border-e {neutralSurface.Border} {transition.TransformFast} {transition.EaseInOut}", NavigationItemBase = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {sizing.MinWidthNone} px-3 py-2 {typography.Size.Sm} {neutralText.Secondary} {neutralSurface.Hover} {focusRingInset} {transition.ColorsFast} {interaction.FocusOutlineNone} {interaction.PointerCursor}", NavigationItemActive = $"{neutralTrack} {neutralText.Heading}", NavigationItemCurrent = $"{positioning.Relative} {overflow.Hidden} before:absolute before:inset-y-0 before:start-0 before:w-0.5 before:bg-linear-to-b before:from-purple-600 before:to-fuchsia-500 forced-colors:before:bg-[Highlight]", NavigationItemParent = typography.Weight.Semibold, NavigationItemIcon = flexbox.ShrinkNone, NavigationItemContent = $"{display.InlineFlex} {flexbox.Align.Center} {flexbox.ShrinkNone} {spacing.PushEnd}", NavigationDropdownContainer = neutralSurface.BackgroundSubtle, NavigationItemActiveLevelDeep = $"border-s-2 {border.Neutral.Strong}", NavigationDropdownContainerDeep = string.Empty, NavigationGroupRailDeep = $"border-s-2 {border.Neutral.Strong}", MainContent = $"overflow-y-auto scrollbar-gutter-stable start-0 {flexbox.Flex1} {sizing.FullWidth} {focusRingInset} {interaction.FocusOutlineNone} transition-[margin] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut}", MainContentRoot = $"{display.Flex} overflow-x-hidden {flexbox.Col} h-dvh {sizing.FullWidth} {transparentBackground} {neutralSurface.Body} {neutralText.Heading} transition-[margin] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut}" }, new TwTreeListTheme { Container = $"{display.Flex} {flexbox.Col} {typography.Size.Sm}", Group = $"{display.Flex} {flexbox.Col} gap-0.5 mt-0.5 ms-3 ps-2 border-s {neutralSurface.Border}", Row = $"group/row {display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm} {sizing.MinWidthNone} {rounded.Md} px-2 py-1.5 {typography.Size.Sm} {neutralText.Heading} {neutralRowHover} [li:focus-visible>&]:ring-inset [li:focus-visible>&]:ring-2 [li:focus-visible>&]:ring-purple-500 dark:[li:focus-visible>&]:ring-purple-400 forced-colors:[li:focus-visible>&]:outline-2 forced-colors:[li:focus-visible>&]:-outline-offset-2 forced-colors:[li:focus-visible>&]:outline-[Highlight] {transition.ColorsFast} {interaction.PointerCursor}", RowDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", ToggleSlot = $"{display.InlineFlex} {flexbox.ShrinkNone} {flexbox.Align.Center} {flexbox.Justify.Center} size-6", ToggleIcon = $"{display.InlineFlex} {flexbox.ShrinkNone} {flexbox.Align.Center} {flexbox.Justify.Center} size-6 {rounded.Full} {neutralText.Muted} {neutralHoverFill} {neutralHoverText} transition-[transform,background-color,color] {transition.DurationFast} motion-reduce:transition-none", ToggleIconOpen = "rotate-90 rtl:-rotate-90", Label = "truncate", ItemIcon = $"{display.InlineFlex} {flexbox.ShrinkNone} {flexbox.Align.Center} {flexbox.Justify.Center} {sizing.Icon.Sm} {neutralText.Muted}", CheckboxWrapper = $"{display.InlineFlex} {flexbox.Align.Center} {flexbox.ShrinkNone} h-4", ItemOutline = "outline-hidden" }, new TwRadioButtonTheme { Colors = checkBoxRadioButtonColors, Base = $"peer {sizing.Icon.Md} {rounded.Full} {borderWidth.Thick} {neutralSurface.BorderStrong} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast} {transition.EaseInOut} {interaction.PointerCursor} appearance-none", Disabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", Hover = $"hover:border-[oklch(21%_0.006_285.885)]/40 dark:hover:border-[oklch(97.807%_0.029_256.847)]/40 {interaction.PointerCursor}", LabelBase = $"{display.Flex} {positioning.Relative} {flexbox.Align.Center} {spacing.Gap.Md} min-h-[24px] {inputLabelText} select-none", LabelInteractiveCursor = interaction.PointerCursor, LabelNonInteractiveCursor = interaction.PointerEventsNone, LabelDisabled = interaction.DisabledOpacity, IconWrapper = $"{positioning.Absolute} start-0 {display.Flex} {flexbox.Align.Center} {flexbox.Justify.Center} {sizing.Icon.Md} opacity-0 peer-checked:opacity-100 {interaction.PointerEventsNone}" }, new TwRatingTheme { Colors = new() { Primary = "text-purple-600 dark:text-purple-400", Accent = "text-fuchsia-600 dark:text-fuchsia-400", Success = "text-green-600 dark:text-green-400", Danger = "text-red-600 dark:text-red-400", Warning = "text-amber-600 dark:text-amber-400", Info = "text-blue-600 dark:text-blue-400", Light = "text-gray-100 dark:text-white", Dark = "text-gray-950 dark:text-gray-950", }, Base = $"{display.InlineFlex} {flexbox.Align.Center} gap-0.5 {rounded.Sm} select-none touch-manipulation", EmptyFocusRing = "has-[input[data-rating-empty]:focus-visible]:ring-2 has-[input[data-rating-empty]:focus-visible]:ring-purple-500 dark:has-[input[data-rating-empty]:focus-visible]:ring-purple-400", Item = $"{positioning.Relative} {display.InlineFlex} {flexbox.ShrinkNone} {rounded.Sm} leading-none", ItemFocusRing = "has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-purple-500 dark:has-[input:focus-visible]:ring-purple-400", ItemHover = $"{transition.TransformFast} {transition.EaseInOut} hover:scale-115 motion-reduce:hover:scale-100", Visual = $"{positioning.Relative} {display.InlineFlex} {interaction.PointerEventsNone}", Empty = "text-[oklch(21%_0.006_285.885)]/30 dark:text-[oklch(97.807%_0.029_256.847)]/30 forced-colors:text-[GrayText]", Clip = $"{positioning.Absolute} inset-y-0 start-0 {display.Flex} {overflow.Hidden} whitespace-nowrap", Filled = $"{flexbox.ShrinkNone} forced-colors:text-[Highlight]", Pop = "tw-rating-pop", Input = "sr-only", HalfTarget = $"{positioning.Absolute} inset-y-0 start-0 z-10 w-1/2 {interaction.PointerCursor}", FullTarget = $"{positioning.Absolute} inset-0 {interaction.PointerCursor}", Disabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", Small = "text-lg", Medium = "text-2xl", Large = "text-4xl" }, new TwSliderTheme { Colors = new() { Primary = $"{background.Medium.Primary} {darkBackground.Medium.Primary}", Accent = $"{background.Medium.Accent} {darkBackground.Medium.Accent}", Success = $"{background.Medium.Success} {darkBackground.Medium.Success}", Danger = $"{background.Medium.Danger} {darkBackground.Medium.Danger}", Warning = $"{background.Medium.Warning} {darkBackground.Medium.Warning}", Info = $"{background.Medium.Info} {darkBackground.Medium.Info}", Light = $"{background.Medium.Light} {darkBackground.Medium.Light}", Dark = $"{background.Dark.Dark} {darkBackground.Dark.Dark}", }, Wrapper = $"{positioning.Relative} {display.Flex} {flexbox.Align.Center} {sizing.FullWidth} h-6 select-none", Base = $"peer {positioning.Absolute} inset-0 z-20 {sizing.Full} m-0 {transparentBackground} appearance-none {interaction.PointerCursor} {interaction.FocusOutlineNone} focus-visible:outline-hidden touch-manipulation", Track = $"{positioning.Absolute} inset-x-0 top-1/2 {overflow.Hidden} h-2 {neutralTrackStrong} {borderWidth.Thin} {neutralSurface.BorderStrong} {rounded.Full} -translate-y-1/2 {interaction.PointerEventsNone}", Fill = $"{sizing.FullHeight} forced-colors:bg-[Highlight]", Thumb = $"{positioning.Absolute} top-1/2 z-10 {sizing.Icon.Md} bg-white dark:bg-gray-100 {rounded.Full} {borderWidth.Thick} -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 {shadows.Md} ring-1 ring-black/5 peer-hover:scale-110 peer-active:scale-95 {transition.TransformFast} {transition.EaseInOut} {interaction.PointerEventsNone}", Bubble = $"{positioning.Absolute} bottom-full z-10 mb-2 px-2 py-1 whitespace-nowrap {typography.Size.Xs} {typography.Weight.Medium} tabular-nums {overlayTheme.Popover.Background} {neutralText.Heading} {overlayTheme.Popover.Border} {rounded.Md} -translate-x-1/2 rtl:translate-x-1/2 {shadows.Lg} opacity-0 scale-95 peer-hover:opacity-100 peer-hover:scale-100 peer-focus-visible:opacity-100 peer-focus-visible:scale-100 transition-[opacity,transform] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut} {interaction.PointerEventsNone}" }, new TwStepperTheme { HorizontalList = $"hidden sm:flex sm:items-start {sizing.FullWidth}", VerticalList = $"{display.Flex} {flexbox.Col} {sizing.FullWidth}", Step = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center} {spacing.Gap.Sm} shrink-0 {typography.AlignCenter}", VerticalStep = $"group {display.Flex} {spacing.Gap.Lg}", VerticalIndicatorColumn = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center}", VerticalContentColumn = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm} {flexbox.Flex1} {sizing.MinWidthNone} pt-2.5 pb-8 group-last:pb-0", Connector = $"{flexbox.Flex1} h-0.5 mt-[19px] mx-1 border-t-2 {rounded.Full} {transition.ColorsSlow}", VerticalConnector = $"{flexbox.Flex1} w-0 min-h-6 my-1 border-s-2 {rounded.Full} {transition.ColorsSlow}", ConnectorNeutral = neutralSurface.Border, Circle = $"{display.Flex} {anchor.Center} shrink-0 {sizing.Icon.Xl} {rounded.Full} {typography.Weight.Semibold} {typography.Size.Sm} {transition.ColorsFast} {interaction.FocusOutlineNone}", CircleUpcoming = $"{neutralSurface.Background} {neutralText.Muted} border-2 {neutralSurface.BorderStrong}", CircleDisabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", CircleClickable = interaction.PointerCursor, CircleFrame = $"{display.InlineFlex} shrink-0 p-0.5 border-2 {rounded.Full} {transition.ColorsFast}", CircleFrameInactive = "border-transparent", CircleUpcomingClickable = $"{neutralRowHover} hover:border-[oklch(21%_0.006_285.885)]/45 dark:hover:border-[oklch(97.807%_0.029_256.847)]/45 {neutralHoverText}", LabelActive = typography.Weight.Semibold, CircleIcon = "leading-none", Label = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Heading}", LabelUpcoming = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Muted}", Description = $"{typography.Size.Xs} {neutralText.Subtle}", Content = $"{spacing.MarginTop.Xl} {spacing.Padding.Xl} {borderWidth.Thin} {neutralSurface.Border} {rounded.Md}", VerticalContent = "pt-2", MobileContainer = $"{display.Flex} sm:hidden {flexbox.Col} {spacing.Gap.Sm} {sizing.FullWidth}", MobileLabel = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Heading}", MobileProgressLabel = display.ScreenReaderOnly }, new TwSwitchTheme { Colors = new() { Primary = "peer-checked:bg-purple-600 dark:peer-checked:bg-purple-500", Accent = "peer-checked:bg-fuchsia-600 dark:peer-checked:bg-fuchsia-500", Success = "peer-checked:bg-green-600 dark:peer-checked:bg-green-500", Danger = "peer-checked:bg-red-600 dark:peer-checked:bg-red-500", Warning = "peer-checked:bg-yellow-600 dark:peer-checked:bg-yellow-500", Info = "peer-checked:bg-blue-600 dark:peer-checked:bg-blue-500", Light = "peer-checked:bg-white dark:peer-checked:bg-gray-300", Dark = "peer-checked:bg-gray-900 dark:peer-checked:bg-gray-800", }, Switch = $"{positioning.Absolute} top-1/2 start-0.5 {sizing.Icon.Md} bg-white {rounded.Full} -translate-y-1/2 {shadows.Md} ring-1 ring-black/15 forced-colors:bg-[ButtonText] peer-checked:translate-x-full rtl:peer-checked:-translate-x-full {transition.TransformFast} {transition.EaseInOut}", Track = $"{positioning.Absolute} inset-0 bg-[oklch(88%_0_0)] dark:bg-[oklch(34%_0.018_253)] {rounded.Full} {neutralHairlineRing} {borderWidth.Thin} {neutralSurface.BorderStrong} forced-colors:peer-checked:bg-[Highlight] peer-disabled:opacity-40 transition-[background-color,opacity] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut} peer-disabled:pointer-events-none", WrapperSize = "w-10 h-6", Base = "peer sr-only", LabelBase = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} {inputLabelText} select-none", LabelInteractiveCursor = interaction.PointerCursor, LabelNonInteractiveCursor = interaction.PointerEventsNone, LabelDisabled = interaction.DisabledOpacity }, new TwSpinnerTheme { Colors = new() { Primary = "border-t-purple-600 dark:border-t-purple-500", Accent = "border-t-fuchsia-600 dark:border-t-fuchsia-500", Success = "border-t-green-600 dark:border-t-green-500", Danger = "border-t-red-600 dark:border-t-red-500", Warning = "border-t-yellow-500 dark:border-t-yellow-500", Info = "border-t-blue-600 dark:border-t-blue-500", Light = "border-t-white", Dark = "border-t-gray-900", }, Wrapper = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md}", Base = $"{display.InlineBlock} {rounded.Full} animate-spin motion-reduce:[animation-duration:3s]", Track = neutralSurface.Border, LightTrack = "border-white/25", DarkTrack = "border-gray-900/15", Small = $"{sizing.Icon.Md} border-3", Medium = $"{sizing.Icon.Xl} border-5", Large = "size-12 border-5", Label = $"{typography.Size.Sm} {neutralText.Muted}" }, new TwTimePickerTheme { PickerRoot = positioning.Relative, IconWrapper = $"{positioning.Absolute} {inset.Top} {inset.Start} {display.Flex} {anchor.Center} w-10 ps-2 {interaction.PointerCursor}", IconGlyph = $"{sizing.Icon.Md} {neutralText.Subtle}", TextfieldPadding = "ps-10 pe-3", NativeInputAppearance = "appearance-none !flex items-center [&::-webkit-date-and-time-value]:min-h-0 [&::-webkit-date-and-time-value]:text-start [&::-webkit-datetime-edit]:p-0", PanelWrapper = $"{positioning.Absolute} top-full start-0 z-120 {spacing.MarginTop.Md}", RangeStageTabsContainer = $"{display.Flex} {spacing.Gap.Sm} {spacing.Padding.Sm} {rounded.Lg} {neutralTrack} {spacing.MarginBottom.Md}", RangeStageTabInactive = neutralText.Subtle, StageTabBase = $"{flexbox.Flex1} py-1.5 {typography.Size.Sm} {typography.Weight.Medium} {typography.AlignCenter} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", StageTabActive = $"bg-white dark:bg-[oklch(34%_0.018_253)] {neutralText.Heading} {shadows.Sm}", StageTabHover = neutralHoverText, BodySurface = $"{spacing.Padding.Xl} {typography.AlignCenter} {typography.Weight.Medium} {neutralText.Heading}", BodyRoot = "", BodyInner = $"{spacing.Padding.Md} {typography.AlignCenter} {typography.Weight.Medium} {neutralText.Heading}", ContentRow = $"{display.Flex} {anchor.Center} {spacing.Gap.Lg}", Column = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center} {spacing.Gap.Sm}", StepButton = $"{neutralText.Subtle} hover:text-purple-600 dark:hover:text-purple-400 {interaction.PointerCursor}", NumberWrapper = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Center}", NumberInput = $"w-12 py-1 {typography.AlignCenter} {typography.Size.Lg} {typography.Weight.Semibold} {neutralText.Heading} {transition.ColorsFast} {rounded.Md} {focusRing} {interaction.FocusOutlineNone}", Separator = $"self-center px-1 {typography.Size.Lg} {typography.Weight.Semibold} {neutralText.Subtle}", AmPmWrapper = $"{display.Flex} {flexbox.Align.Center} ms-2", AmPmButtonClass = "min-w-12" }, new TwTableTheme { Wrapper = $"{positioning.Relative} overflow-auto focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-purple-600 dark:focus-visible:outline-purple-300", ContainerClip = overflow.Hidden, Base = $"{sizing.FullWidth} {typography.Size.Sm} text-start {neutralText.Heading}", FixedLayout = "table-fixed", Bordered = $"{borderWidth.Thin} {neutralSurface.Border}", Header = $"{typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Secondary} {neutralSurface.BackgroundSubtle} border-b {neutralSurface.Border}", StickyHeader = $"{positioning.Sticky} top-0 z-10", Body = neutralSurface.Background, BodyStriped = "[&>tr:nth-child(even)]:bg-[oklch(98%_0_0)] [&>tr:nth-child(even)]:dark:bg-[oklch(23.26%_0.014_253.1)]", BodyHoverable = "[&>tr:hover]:!bg-[oklch(95%_0_0)] [&>tr:hover]:dark:!bg-[oklch(21.15%_0.012_254.09)] [&>tr]:transition-colors [&>tr]:duration-200 [&>tr]:motion-reduce:transition-none", RowDivider = "divide-y divide-[oklch(94%_0_0)] dark:divide-[oklch(21.15%_0.012_254.09)]", Footer = $"border-t {neutralSurface.Border}", SearchColumn = "md:w-1/2", SortIcon = $"{typography.Size.Sm} {neutralText.Subtle} {neutralHoverText}", HeaderCellPadding = "px-4 py-2.5", BodyCellPadding = $"px-4 py-2.5 {typography.WrapBreakWord}", EmptyState = $"py-8 {typography.AlignCenter} {neutralText.Muted}", ResizeHandle = $"{positioning.Absolute} z-20 flex w-3 -translate-x-1/2 justify-center cursor-col-resize touch-none select-none before:block before:h-full before:w-px before:bg-gray-300 dark:before:bg-gray-600 hover:before:w-0.5 hover:before:bg-purple-500 active:before:bg-purple-600 dark:hover:before:bg-purple-400 focus-visible:outline-none focus-visible:before:w-0.5 focus-visible:before:bg-purple-600 dark:focus-visible:before:bg-purple-300", GroupByColumn = "w-full sm:w-56", GroupRow = $"{neutralSurface.BackgroundSubtle} {neutralText.Heading}", GroupToggle = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Sm} {rounded.Md} -mx-1 px-1 {typography.Weight.Semibold} {interaction.PointerCursor} focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-purple-600 dark:focus-visible:outline-purple-300", GroupCount = $"{typography.Weight.Medium} {neutralText.Muted}", LoadingCell = $"py-2.5 {typography.AlignCenter} {neutralText.Muted}", ActionsCell = "w-px whitespace-nowrap", EditingRow = "!bg-purple-50 dark:!bg-purple-500/10", FilterPanel = $"z-50 w-72 max-w-[calc(100vw-1rem)] {rounded.Lg} {borderWidth.Thin} {neutralSurface.Border} {neutralSurface.Background} shadow-lg {spacing.Padding.Md} {interaction.FocusOutlineNone}", FilterHeading = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm} {spacing.MarginBottom.Md} {typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Heading}" }, new TwToastTheme { Colors = new() { Primary = $"{background.Light.Primary} {darkBackground.Light.Primary} {text.Dark.Primary} {borderWidth.AccentEdge} {borderColors.Primary}", Accent = $"{background.Light.Accent} {darkBackground.Light.Accent} {text.Dark.Accent} {borderWidth.AccentEdge} {borderColors.Accent}", Success = $"{background.Light.Success} {darkBackground.Light.Success} {text.Dark.Success} {borderWidth.AccentEdge} {borderColors.Success}", Danger = $"{background.Light.Danger} {darkBackground.Light.Danger} {text.Dark.Danger} {borderWidth.AccentEdge} {borderColors.Danger}", Warning = $"{background.Light.Warning} {darkBackground.Light.Warning} {text.Dark.Warning} {borderWidth.AccentEdge} {borderColors.Warning}", Info = $"{background.Light.Info} {darkBackground.Light.Info} {text.Dark.Info} {borderWidth.AccentEdge} {borderColors.Info}", Light = $"{background.Light.Light} {darkBackground.Light.Light} {text.Dark.Dark} {borderWidth.AccentEdge} {borderColors.Light}", Dark = $"{background.Dark.Dark} {text.Light.Light} {borderWidth.AccentEdge} {borderColors.Dark}" }, HeaderClasses = $"{display.Flex} {flexbox.Col} {flexbox.Flex1} {spacing.Gap.Md} {sizing.MinWidthNone}", IconContainer = flexbox.ShrinkNone, Title = $"{typography.Weight.Semibold} {typography.Size.Sm} {typography.WrapBreakWord}", Message = $"{typography.Size.Sm} {typography.WrapBreakWord}", Container = $"{positioning.Fixed} bottom-0 end-4 z-140 {display.Flex} {flexbox.Col} {spacing.Gap.Md} max-w-md {spacing.Padding.Xl}", Toast = $"{display.Flex} {flexbox.Align.Start} {spacing.Gap.Md} {spacing.Padding.Xl} {shadows.Lg} {transition.ColorsFast} {transition.EaseInOut}", ToastWidth = "w-[300px] max-w-full", Timestamp = $"{typography.Size.Xs} opacity-70", CloseButton = $"{flexbox.ShrinkNone} {spacing.Padding.Sm} {neutralHoverFill} {rounded.Full} focus-visible:ring-2 focus-visible:ring-current {transition.ColorsFast} {interaction.FocusOutlineNone}" }, new TwCalendarTheme { Container = $"{display.Flex} {flexbox.Col} {sizing.FullWidth} {spacing.Gap.Lg}", Header = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {flexbox.Wrap} {spacing.Gap.Lg} pb-4 border-b {neutralSurface.Border}", HeaderDateGroup = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm}", HeaderTitleRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md}", HeaderTitle = $"{typography.Size.Lg} {typography.Weight.Semibold} {neutralText.Heading}", HeaderSubtitle = $"{typography.Size.Xs} {neutralText.Muted}", NavButton = $"{display.Flex} {anchor.Center} size-8 {rounded.Full} {neutralSurface.Hover} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast}", ViewButtonActive = $"{background.Lightest.Primary} {darkBackground.Dark.Primary}", AddButton = "shrink-0", SearchButton = neutralText.Subtle, ScrollContainer = "overflow-y-auto", TimeGutter = $"{positioning.Relative} {display.Flex} {flexbox.Col} {flexbox.ShrinkNone} w-10 sm:w-16 text-end {spacing.Padding.Sm}", TimeGutterLabel = $"text-[10px] sm:text-xs {neutralText.Subtle} -translate-y-2", NowIndicatorLabel = $"{positioning.Absolute} end-1 sm:end-2 -translate-y-1/2 text-[10px] sm:text-xs {typography.Weight.Semibold} {text.Medium.Primary} {darkText.Light.Primary} {neutralSurface.Background} px-1 {rounded.Sm} {interaction.PointerEventsNone}", NowIndicatorLine = $"{positioning.Absolute} inset-x-0 border-t-2 {borderColors.Primary} {interaction.PointerEventsNone} z-10", NowIndicatorDot = $"{positioning.Absolute} -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 size-2.5 {rounded.Full} {background.Medium.Primary} {interaction.PointerEventsNone} z-10", SlotRow = $"h-12 border-t {neutralSurface.BorderSubtle}", SlotRowHover = $"{neutralSurface.Hover} {interaction.PointerCursor}", DayColumnHeader = $"{sizing.MinWidthNone} {typography.Size.Xs} {typography.Weight.Semibold} {typography.AlignCenter} {neutralText.Secondary} py-2 border-b {neutralSurface.Border} {focusRingInset} {interaction.FocusOutlineNone}", DayColumnHeaderLabel = "sr-only sm:not-sr-only", DayColumnHeaderCompact = "gap-0.5 sm:hidden", DayColumnHeaderWeekday = $"text-[10px] {typography.Weight.Medium} {textTransform.Uppercase} {neutralText.Subtle}", DayColumnHeaderDayNumber = $"{display.Flex} {anchor.Center} size-7 {rounded.Full} {typography.Size.Sm} {neutralText.Heading}", DayColumnHeaderDayNumberToday = $"{background.Medium.Primary} {text.Medium.Light}", DayColumnDivider = $"border-s {neutralSurface.BorderSubtle}", EventChip = $"{positioning.Absolute} {overflow.Hidden} {rounded.Sm} {display.Flex} {flexbox.Col} {flexbox.Align.Start} text-start {borderWidth.AccentEdge} {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} {spacing.Padding.Sm} {interaction.PointerCursor} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast}", EventChipTitle = $"{typography.Size.Xs} {typography.Weight.Semibold} {typography.WrapBreakWord}", EventChipTime = $"{typography.Size.Xs} opacity-75", EventChipCompact = "max-sm:border-s-2 max-sm:px-0.5", EventChipTitleCompact = "max-sm:text-[10px] max-sm:leading-tight", EventChipTimeCompact = "max-sm:hidden", EventChipReadOnly = $"{interaction.ReadonlyCursor} opacity-90", EventChipDraggable = "cursor-grab active:cursor-grabbing", DropPlaceholder = $"{overflow.Hidden} {rounded.Sm} border-2 border-dashed {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} {typography.Size.Xs} opacity-70 z-10", TodayHighlight = $"animate-pulse motion-reduce:animate-none [animation-iteration-count:1] {background.Light.Primary} dark:bg-purple-500/50", AllDayRow = $"border-b {neutralSurface.Border}", AllDayLabel = $"{flexbox.ShrinkNone} w-10 sm:w-16 {spacing.Padding.Sm} text-end text-[10px] sm:text-xs {neutralText.Subtle}", AllDayGrid = "gap-y-1 py-1", AllDayChipInset = "mx-0.5", SegmentSpan = $"{positioning.Relative} z-10", SegmentContinuesBefore = "rounded-s-none", SegmentContinuesAfter = "rounded-e-none", SegmentSpacer = $"h-5 {flexbox.ShrinkNone}", MonthGrid = $"{sizing.FullWidth} border-collapse table-fixed", MonthCell = $"align-top {spacing.Padding.Sm} max-sm:p-0.5 border {neutralSurface.BorderSubtle} h-24", MonthCellPrevNext = $"{neutralSurface.BackgroundSubtle} {neutralText.Subtle}", MonthDayNumber = $"{display.Block} {sizing.FullWidth} text-start {typography.Size.Xs} {typography.Weight.Medium} {neutralText.Heading}", MonthEventList = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm} mt-1", MonthEventRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm} {sizing.FullWidth} {overflow.Hidden} {rounded.Sm} text-start max-sm:border-s-2 max-sm:px-0.5 {borderWidth.AccentEdge} {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} px-1.5 py-0.5 {interaction.PointerCursor} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast}", MonthEventName = $"{typography.Size.Xs} max-sm:text-[10px] {typography.Weight.Semibold} truncate max-sm:text-clip", MonthEventTime = $"{typography.Size.Xs} opacity-75 {flexbox.ShrinkNone} max-sm:hidden", MonthOverflowLabel = $"{typography.Size.Xs} max-sm:text-[10px] text-start whitespace-nowrap {neutralText.Subtle} {interaction.PointerCursor}", EventDialogFields = $"{display.Flex} {flexbox.Col} {spacing.Gap.Xl} -mt-3", EventDialogActions = $"{display.Flex} {flexbox.Justify.End} {spacing.Gap.Md} {spacing.MarginTop.Xl}", EventDialogAccent = $"h-1 {sizing.FullWidth} {rounded.Full} {background.Medium.Primary}", EventDialogDateRow = $"{display.Grid} grid-cols-1 sm:grid-cols-2 {spacing.Gap.Xl}", EventDialogSummary = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Lg} {rounded.Md} {borderWidth.AccentEdge} {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {neutralText.Heading} {spacing.Padding.Lg} {typography.Size.Sm}", EventDialogSummaryIcon = $"{flexbox.ShrinkNone} {text.Medium.Primary} {darkText.Light.Primary}", EventDialogReadOnlyField = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm}", EventDialogReadOnlyLabel = $"{typography.Size.Xs} font-normal tracking-wide {neutralText.Muted}", EventDialogReadOnlyValue = $"{typography.Size.Base} {neutralText.Heading} whitespace-pre-line" } ] }; } ``` This is the default theme. To use your own brand colors or only the components you use, [build your own Theme.cs](https://twblazor.com/theme) instead, and register it with `Theme.CreateTheme` in step 7. ### 7. Register TwBlazor services In `{YourProjectName}/Program.cs`, register TwBlazor's services using the theme you just configured. ```csharp builder.Services.AddTwBlazor(_ => { }, Theme.CreateDefaultTheme); ``` ### 8. Build your Tailwind CSS TwBlazor doesn't ship a pre-built stylesheet - since Tailwind can't compile classes from a .DLL, every class TwBlazor's components use is also expressed as a literal in the `Theme.cs` you just wrote, so your own Tailwind build produces the whole thing in one pass. Install the [Tailwind CLI](https://tailwindcss.com/docs/installation/tailwind-cli) from the solution root (the folder containing `{YourProjectName}.csproj`): ```bash npm init -y npm install tailwindcss @tailwindcss/cli ``` Create an input stylesheet at `{YourProjectName}/wwwroot/css/input.css`. The `@source` directives tell Tailwind to scan your razor components and `Theme.cs` for classes to generate. The keyframes at the bottom power `TwSkeleton`'s `Wave` variant - a shimmer effect Tailwind has no utility for, so it has to be real CSS rather than a class Tailwind can generate. Skip it if you don't use that variant: ```css @import "tailwindcss"; @source "../../**/*.razor"; @source "../../Theme.cs"; /* Powers TwSkeleton's wave animation and TwProgress's Animated shimmer. */ @keyframes tw-wave { 0% { transform: translateX(-100%); } 50%, 100% { transform: translateX(100%); } } .tw-wave::after { content: ""; position: absolute; inset: 0; transform: translateX(-100%); background: linear-gradient(90deg, transparent, var(--tw-wave-color, rgb(255 255 255 / 40%)), transparent); animation: tw-wave 1.6s linear infinite; } .dark .tw-wave::after { background: linear-gradient(90deg, transparent, var(--tw-wave-color, rgb(255 255 255 / 8%)), transparent); } /* Powers TwIcons's pulse animation */ .tw-icon-pulse::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background-color: currentColor; opacity: 0; transform: scale(0); transition: transform 500ms ease-out, opacity 450ms ease-out; pointer-events: none; } .tw-icon-pulse:active::after { opacity: 0.25; transform: scale(1); transition: transform 120ms ease-out, opacity 80ms ease-out; } /* Powers TwRating's "pop" when a rating is picked: a quick overshoot that settles back. Each pick flips the element's data-pop between 0 and 1, and with it the keyframe name, because re-applying the same animation to an element does not replay it. */ @keyframes tw-rating-pop { 0% { transform: scale(1); } 35% { transform: scale(1.35); } 65% { transform: scale(0.92); } 100% { transform: scale(1); } } @keyframes tw-rating-pop-alt { 0% { transform: scale(1); } 35% { transform: scale(1.35); } 65% { transform: scale(0.92); } 100% { transform: scale(1); } } .tw-rating-pop { animation: tw-rating-pop 420ms ease-out both; } .tw-rating-pop[data-pop="1"] { animation-name: tw-rating-pop-alt; } @media (prefers-reduced-motion: reduce) { .tw-wave::after { animation: none; } .tw-icon-pulse::after { transition: none; } .tw-rating-pop { animation: none; } } ``` Then build it to `{YourProjectName}/wwwroot/css/output.css`, the file already referenced by the `` tag you added to App.razor in step 3: ```bash npx @tailwindcss/cli -i ./wwwroot/css/input.css -o ./wwwroot/css/output.css --watch ``` ### 9. Try it out Add a test page to confirm everything is wired up. Create `{YourProjectName}/Components/Pages/ComponentTest.razor`: ```razor @page "/component-test" @rendermode InteractiveServer Component Test

Component Test

Everything below is wired up and interactive - you're good to go!
``` ```csharp private int count; private bool switchOne; private bool switchTwo = true; private bool switchThree; private void Increment() => count++; ``` Run the app and go to `/component-test`. You should see a green success alert, a button whose label counts up each click, and three interactive switches. ## Blazor WebAssembly ### 1. Create the project Scaffold a new Blazor Web App with WebAssembly interactivity. Unlike the Server model, this creates **two** projects side by side. Replace `{YourProjectName}` with your own project's name. ```bash dotnet new blazor -o {YourProjectName} --interactivity WebAssembly ``` ```text {YourProjectName}/ {YourProjectName}/ <- ASP.NET Core host project: Program.cs starts the web server and serves the WebAssembly payload. App.razor, Routes.razor and any statically-rendered pages live here. {YourProjectName}.Client/ <- The Blazor WebAssembly project that actually runs in the browser. Program.cs builds a WebAssemblyHost. Layout/MainLayout.razor, Layout/NavMenu.razor and any interactive pages live here, because only code compiled into this project can run client-side. ``` Every step below tells you which of the two projects a file belongs in. ### 2. Install the twblazor NuGet package Install the [twblazor NuGet package](https://www.nuget.org/packages/twblazor) in **both** projects. `{YourProjectName}.Client` needs it because the interactive layout and providers are compiled into it; `{YourProjectName}` needs it too because it references `{YourProjectName}.Client`'s `Theme` class and still renders those components on the server before the WebAssembly bundle takes over. ```bash cd {YourProjectName} dotnet add package twblazor --version 2.1.2 cd ../{YourProjectName}.Client dotnet add package twblazor --version 2.1.2 ``` ### 3. Add to App.razor App.razor always lives in the host project, even in the WebAssembly model. In `{YourProjectName}/Components/App.razor`, add the same two stylesheet links as before - the Bootstrap Icons stylesheet, and a link to your own project's Tailwind build, which won't exist until step 8. ```razor ``` At the bottom of the body, include the twblazor.js script. Note the render mode is `InteractiveWebAssembly` instead of `InteractiveServer`. ```razor ``` ### 4. Add to _Imports.razor Add the following to `{YourProjectName}.Client/_Imports.razor`, since that's where your interactive components (like MainLayout.razor) live: ```razor @using TwBlazor.Components @using TwBlazor.Enums @using TwBlazor ``` ### 5. Add the TwBlazor providers to MainLayout.razor This is the one step that differs structurally from the Server model. TwToastProvider and TwDialogProvider rely on JS interop, so they must run on a component that supports interactive rendering. App.razor is always statically rendered, so the providers can't go there. Instead, add them to the top of `{YourProjectName}.Client/Layout/MainLayout.razor` - only code compiled into `{YourProjectName}.Client` can run under WebAssembly. ```razor @inherits LayoutComponentBase @Body
An unhandled error has occurred. Reload 🗙
``` ### 6. Add a TwTheme Since Tailwind CSS cannot compile classes from .DLLs, you configure the theme's classes in your own project. Create a `Theme.cs` file at the root of the `{YourProjectName}.Client` project - not `{YourProjectName}` - since that's where the components using this theme are compiled. ```csharp public static TwBlazorTheme CreateDefaultTheme() { var flexbox = new TwBlazorFlexbox { Row = "flex-row", RowReverse = "flex-row-reverse", Col = "flex-col", ColReverse = "flex-col-reverse", Wrap = "flex-wrap", NoWrap = "flex-nowrap", WrapReverse = "flex-wrap-reverse", Grow = "grow", GrowNone = "grow-0", Shrink = "shrink", ShrinkNone = "shrink-0", Flex1 = "flex-1", Justify = new() { Start = "justify-start", Center = "justify-center", End = "justify-end", Between = "justify-between", Around = "justify-around", Evenly = "justify-evenly" }, Align = new() { Start = "items-start", Center = "items-center", End = "items-end", Stretch = "items-stretch", Baseline = "items-baseline" }, AlignContent = new() { Start = "content-start", Center = "content-center", End = "content-end", Between = "content-between", Around = "content-around", Evenly = "content-evenly", Stretch = "content-stretch" }, AlignSelf = new() { Start = "self-start", Center = "self-center", End = "self-end", Stretch = "self-stretch", Baseline = "self-baseline" } }; var anchor = new TwAnchorPosition { Center = $"{flexbox.Align.Center} {flexbox.Justify.Center}", CenterLeft = $"{flexbox.Align.Center} {flexbox.Justify.Start}", CenterRight = $"{flexbox.Align.Center} {flexbox.Justify.End}", TopCenter = $"{flexbox.Align.Start} {flexbox.Justify.Center}", TopLeft = $"{flexbox.Align.Start} {flexbox.Justify.Start}", TopRight = $"{flexbox.Align.Start} {flexbox.Justify.End}", BottomCenter = $"{flexbox.Align.End} {flexbox.Justify.Center}", BottomLeft = $"{flexbox.Align.End} {flexbox.Justify.Start}", BottomRight = $"{flexbox.Align.End} {flexbox.Justify.End}", }; var text = new TwTextColor { Light = { Primary = "text-purple-200", Accent = "text-fuchsia-200", Success = "text-green-200", Danger = "text-red-200", Warning = "text-yellow-200", Info = "text-blue-200", Light = "text-white", Dark = "text-gray-200" }, Medium = { Primary = "text-purple-600", Accent = "text-fuchsia-700", Success = "text-green-800", Danger = "text-red-700", Warning = "text-yellow-800", Info = "text-blue-600", Light = "text-gray-100", Dark = "text-gray-950", }, Dark = { Primary = "text-purple-900", Accent = "text-fuchsia-900", Success = "text-green-900", Danger = "text-red-900", Warning = "text-yellow-900", Info = "text-blue-900", Light = "text-gray-300", Dark = "text-gray-900" } }; var darkText = new TwTextColor { Light = { Primary = "dark:text-purple-200", Accent = "dark:text-fuchsia-200", Success = "dark:text-green-200", Danger = "dark:text-red-200", Warning = "dark:text-yellow-200", Info = "dark:text-blue-200", Dark = "dark:text-gray-200" }, Medium = { Primary = "dark:text-purple-600", Accent = "dark:text-fuchsia-600", Success = "dark:text-green-600", Danger = "dark:text-red-600", Warning = "dark:text-yellow-600", Info = "dark:text-blue-600", Light = "dark:text-white", Dark = "dark:text-gray-950", }, Dark = { Primary = "dark:text-purple-900", Accent = "dark:text-fuchsia-900", Success = "dark:text-green-900", Danger = "dark:text-red-900", Warning = "dark:text-yellow-900", Info = "dark:text-blue-900", Dark = "dark:text-gray-900" } }; var borderColors = new TwBlazorPalette { Primary = "border-purple-600 dark:border-purple-500", Accent = "border-fuchsia-600 dark:border-fuchsia-400", Success = "border-green-600 dark:border-green-400", Danger = "border-red-600 dark:border-red-400", Warning = "border-yellow-700 dark:border-yellow-400", Info = "border-blue-600 dark:border-blue-400", Light = "border-gray-100 dark:border-gray-700", Dark = "border-gray-900 dark:border-gray-700" }; var hoverColors = new TwBlazorPalette { Primary = "hover:bg-purple-50 dark:hover:bg-purple-900/20", Accent = "hover:bg-fuchsia-50 dark:hover:bg-fuchsia-900/20", Success = "hover:bg-green-50 dark:hover:bg-green-900/20", Danger = "hover:bg-red-50 dark:hover:bg-red-900/20", Warning = "hover:bg-yellow-50 dark:hover:bg-yellow-900/20", Info = "hover:bg-blue-50 dark:hover:bg-blue-900/20", Light = "hover:bg-gray-100/10", Dark = "hover:bg-gray-900/10 dark:hover:bg-white/10" }; var background = new TwBackgroundColor { Lightest = new() { Primary = $"bg-purple-50", Accent = $"bg-fuchsia-50", Success = $"bg-green-50", Danger = $"bg-red-50", Warning = $"bg-yellow-50", Info = $"bg-blue-50", Light = $"bg-white", Dark = $"bg-gray-50" }, Light = new() { Primary = $"bg-purple-200", Accent = $"bg-fuchsia-200", Success = $"bg-green-200", Danger = $"bg-red-200", Warning = $"bg-yellow-200", Info = $"bg-blue-200", Light = $"bg-white", Dark = $"bg-gray-200" }, Medium = new() { Primary = $"bg-purple-600", Accent = $"bg-fuchsia-600", Success = $"bg-green-700", Danger = $"bg-red-600", Warning = $"bg-yellow-600", Info = $"bg-blue-600", Light = $"bg-gray-100", Dark = $"bg-gray-600", }, Dark = new() { Primary = $"bg-purple-900", Accent = $"bg-fuchsia-900", Success = $"bg-green-900", Danger = $"bg-red-900", Warning = $"bg-yellow-900", Info = $"bg-blue-900", Light = $"bg-gray-300", Dark = $"bg-gray-900" }, Darkest = new() { Primary = $"bg-purple-950", Accent = $"bg-fuchsia-950", Success = $"bg-green-950", Danger = $"bg-red-950", Warning = $"bg-yellow-950", Info = $"bg-blue-950", Light = $"bg-gray-950", Dark = $"bg-black" } }; var darkBackground = new TwBackgroundColor { Lightest = new() { Primary = $"dark:bg-purple-50", Accent = $"dark:bg-fuchsia-50", Success = $"dark:bg-green-50", Danger = $"dark:bg-red-50", Warning = $"dark:bg-yellow-50", Info = $"dark:bg-blue-50", Dark = $"dark:bg-gray-50" }, Light = new() { Primary = $"dark:bg-purple-200", Accent = $"dark:bg-fuchsia-200", Success = $"dark:bg-green-200", Danger = $"dark:bg-red-200", Warning = $"dark:bg-yellow-200", Info = $"dark:bg-blue-200", Dark = $"dark:bg-gray-200", }, Medium = new() { Primary = $"dark:bg-purple-600", Accent = $"dark:bg-fuchsia-600", Success = $"dark:bg-green-600", Danger = $"dark:bg-red-600", Warning = $"dark:bg-yellow-600", Info = $"dark:bg-blue-600", Light = $"dark:bg-white", Dark = $"dark:bg-gray-600", }, Dark = new() { Primary = $"dark:bg-purple-900", Accent = $"dark:bg-fuchsia-900", Success = $"dark:bg-green-900", Danger = $"dark:bg-red-900", Warning = $"dark:bg-yellow-900", Info = $"dark:bg-blue-900", Dark = $"dark:bg-gray-900", }, Darkest = new() { Primary = $"dark:bg-purple-950", Accent = $"dark:bg-fuchsia-950", Success = $"dark:bg-green-950", Danger = $"dark:bg-red-950", Warning = $"dark:bg-yellow-950", Info = $"dark:bg-blue-950", Dark = $"dark:bg-black", } }; var checkBoxRadioButtonColors = new TwBlazorPalette() { Primary = "checked:bg-purple-600 checked:border-purple-600 dark:checked:bg-purple-500 dark:checked:border-purple-500", Accent = "checked:bg-fuchsia-600 checked:border-fuchsia-600 dark:checked:bg-fuchsia-500 dark:checked:border-fuchsia-500", Success = "checked:bg-green-600 checked:border-green-600 dark:checked:bg-green-500 dark:checked:border-green-500", Danger = "checked:bg-red-600 checked:border-red-600 dark:checked:bg-red-500 dark:checked:border-red-500", Warning = "checked:bg-yellow-700 checked:border-yellow-700 dark:checked:bg-yellow-500 dark:checked:border-yellow-500", Info = "checked:bg-blue-600 checked:border-blue-600 dark:checked:bg-blue-500 dark:checked:border-blue-500", Light = "checked:bg-white checked:border-gray-900 dark:checked:bg-white dark:checked:border-gray-500", Dark = "checked:bg-gray-900 checked:border-gray-900 dark:checked:bg-gray-900 dark:checked:border-gray-900" }; var neutralSurface = new TwSurfacePalette { Background = "bg-[oklch(100%_0_0)] dark:bg-[oklch(25.33%_0.016_252.42)]", Body = "bg-[oklch(98.5%_0_0)] dark:bg-[oklch(22.2%_0.015_253)]", BackgroundSubtle = "bg-[oklch(98%_0_0)] dark:bg-[oklch(23.26%_0.014_253.1)]", Border = "border-[oklch(92%_0_0)] dark:border-[oklch(21.15%_0.012_254.09)]", BorderSubtle = "border-[oklch(98%_0_0)] dark:border-[oklch(23.26%_0.014_253.1)]", Hover = "hover:bg-[oklch(98%_0_0)] dark:hover:bg-[oklch(23.26%_0.014_253.1)]", Elevated = "bg-[oklch(97%_0_0)] dark:bg-[oklch(34%_0.018_253)]", Overlay = "bg-[oklch(100%_0_0)] dark:bg-[oklch(40%_0.016_253)]", BorderStrong = "border-[oklch(21%_0.006_285.885)]/50 dark:border-[oklch(97.807%_0.029_256.847)]/45" }; var neutralText = new TwNeutralTextPalette { Heading = "text-[oklch(21%_0.006_285.885)] dark:text-[oklch(97.807%_0.029_256.847)]", Secondary = "text-[oklch(40%_0.006_285.885)] dark:text-[oklch(88%_0.02_256.847)]", Muted = "text-[oklch(50%_0.006_285.885)] dark:text-[oklch(78%_0.02_256.847)]", Subtle = "text-[oklch(55%_0.006_285.885)] dark:text-[oklch(68%_0.02_256.847)]" }; // One height for every single-line input (and the controls laid out beside them, e.g. pagination), // so they all line up whichever component renders them. var inputHeight = "h-10"; var inputDenseHeight = "h-8"; // Single focus language for every focusable surface: a 2px primary ring. The inset form is for rows // that sit flush against their container's edge and would otherwise have the ring clipped. var focusRing = "focus-visible:ring-2 focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400"; var focusRingInset = "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400"; // Neutral fills reused wherever a component needs a recessed track, a selected row or a pressed state. var neutralTrack = "bg-[oklch(95%_0_0)] dark:bg-[oklch(21.15%_0.012_254.09)]"; // A recessed track that stays visible on a white card: progress and slider tracks carry the value, so // they need more contrast than the page-chrome fill above. var neutralTrackStrong = "bg-[oklch(91%_0_0)] dark:bg-[oklch(32%_0.016_253)]"; var neutralHoverText = "hover:text-[oklch(21%_0.006_285.885)] dark:hover:text-[oklch(97.807%_0.029_256.847)]"; var neutralRowHover = "hover:bg-[oklch(21%_0.006_285.885)]/5 dark:hover:bg-[oklch(97.807%_0.029_256.847)]/8"; var neutralHoverFill = "hover:bg-[oklch(21%_0.006_285.885)]/10 dark:hover:bg-[oklch(97.807%_0.029_256.847)]/10"; var neutralHairlineRing = "ring-1 ring-inset ring-[oklch(21%_0.006_285.885)]/10 dark:ring-[oklch(97.807%_0.029_256.847)]/15"; var disabledInk = "text-[oklch(21%_0.006_285.885)]/40 dark:text-[oklch(97.807%_0.029_256.847)]/40"; var inputLabelText = $"text-xs font-normal tracking-wide {neutralText.Muted}"; var display = new TwBlazorDisplay { Block = "block", InlineBlock = "inline-block", Flex = "flex", InlineFlex = "inline-flex", Grid = "grid", InlineGrid = "inline-grid", Hidden = "hidden", Contents = "contents", ScreenReaderOnly = "sr-only" }; var spacing = new TwBlazorSpacing { Gap = new() { Sm = "gap-1", Md = "gap-2", Lg = "gap-3", Xl = "gap-4" }, InteractiveRowPadding = "px-4 py-3", PushEnd = "ms-auto", Padding = new() { Sm = "p-1", Md = "p-2", Lg = "p-3", Xl = "p-4" }, Margin = new() { Sm = "m-1", Md = "m-2", Lg = "m-3", Xl = "m-4" }, MarginTop = new() { Sm = "mt-1", Md = "mt-2", Lg = "mt-3", Xl = "mt-4" }, MarginBottom = new() { Sm = "mb-1", Md = "mb-2", Lg = "mb-3", Xl = "mb-4" }, PaddingTop = new() { Sm = "pt-1", Md = "pt-2", Lg = "pt-3", Xl = "pt-4" }, PaddingStart = new() { Sm = "ps-1", Md = "ps-2", Lg = "ps-3", Xl = "ps-4" }, MarginStart = new() { Sm = "ms-1", Md = "ms-2", Lg = "ms-3", Xl = "ms-4" }, MarginEnd = new() { Sm = "me-1", Md = "me-2", Lg = "me-3", Xl = "me-4" } }; var interaction = new TwBlazorInteraction { DisabledOpacity = "opacity-40", PointerCursor = "cursor-pointer", DisabledCursor = "cursor-not-allowed", ReadonlyCursor = "cursor-default", PointerEventsNone = "pointer-events-none", FocusOutlineNone = "focus:outline-hidden" }; var sizing = new TwBlazorSizing { FullWidth = "w-full", FullHeight = "h-full", Full = "w-full h-full", MinWidthNone = "min-w-0", Icon = new() { Xs = "size-3", Sm = "size-4", Md = "size-5", Lg = "size-6", Xl = "size-8" } }; var overflow = new TwBlazorOverflow { Hidden = "overflow-hidden" }; var transition = new TwBlazorTransition { Colors = "transition-colors motion-reduce:transition-none", Transform = "transition-transform motion-reduce:transition-none", EaseInOut = "ease-in-out", DurationFast = "duration-200", DurationSlow = "duration-300" }; transition.ColorsFast = $"{transition.Colors} {transition.DurationFast}"; transition.ColorsSlow = $"{transition.Colors} {transition.DurationSlow}"; transition.TransformFast = $"{transition.Transform} {transition.DurationFast}"; transition.TransformSlow = $"{transition.Transform} {transition.DurationSlow}"; var typography = new TwBlazorTypography { Size = new() { Xs = "text-xs", Sm = "text-sm", Base = "text-base", Lg = "text-lg" }, Weight = new() { Medium = "font-medium", Semibold = "font-semibold" }, AlignCenter = "text-center", WrapBreakWord = "wrap-break-word" }; var rounded = new TwBlazorRounded { None = "rounded-none", Sm = "rounded-sm", Md = "rounded", Lg = "rounded-lg", Full = "rounded-full", DefaultRounded = Rounded.Lg, RoundedTop = new() { None = "rounded-t-none", Sm = "rounded-t-sm", Md = "rounded-t", Lg = "rounded-t-lg", Full = "rounded-t-full" }, RoundedBottom = new() { None = "rounded-b-none", Sm = "rounded-b-sm", Md = "rounded-b", Lg = "rounded-b-lg", Full = "rounded-b-full" }, RoundedStart = new() { None = "rounded-s-none", Sm = "rounded-s-sm", Md = "rounded-s", Lg = "rounded-s-lg", Full = "rounded-s-full" }, RoundedEnd = new() { None = "rounded-e-none", Sm = "rounded-e-sm", Md = "rounded-e", Lg = "rounded-e-lg", Full = "rounded-e-full" } }; var shadows = new TwBlazorShadow { None = "shadow-none", Sm = "shadow-sm", Md = "shadow", Lg = "shadow-lg", Xl = "shadow-xl", HoverSm = "hover:shadow-sm", HoverMd = "hover:shadow", HoverLg = "hover:shadow-xl", ActiveMd = "active:shadow", DefaultShadow = Shadow.Sm }; var borderWidth = new TwBlazorBorderWidth { None = "border-0", Thin = "border", Medium = "border-[1.2px]", Thick = "border-2", AccentEdge = "border-s-4" }; // Combined border home: one width scale plus semantic and neutral color, so a component theme // never has to reach into three separate places to build a border class. var border = new TwBlazorBorder { Width = borderWidth, Colors = borderColors, Neutral = new() { Base = neutralSurface.Border, Subtle = neutralSurface.BorderSubtle, Strong = neutralSurface.BorderStrong } }; var positioning = new TwBlazorPositioning { Static = "static", Relative = "relative", Absolute = "absolute", Fixed = "fixed", Sticky = "sticky" }; var inset = new TwBlazorInset { Top = "top-0", Bottom = "bottom-0", Start = "start-0", End = "end-0" }; var textTransform = new TwBlazorTextTransform { Uppercase = "uppercase", Lowercase = "lowercase", Capitalize = "capitalize", NormalCase = "normal-case" }; var transparentBackground = "bg-transparent"; var overlayTheme = new TwOverlayTheme { Popover = new TwPopoverTheme { Background = neutralSurface.Overlay, Border = $"{borderWidth.Thin} {neutralSurface.BorderStrong}", TimeRangeSize = $"w-56 {spacing.Padding.Md}", ColorSize = $"tw-color-picker-dialog w-64 {spacing.Padding.Lg}" }, Dialog = new TwDialogTheme { Background = neutralSurface.Background, Backdrop = $"{positioning.Fixed} inset-0 z-110 {display.Flex} overflow-y-auto overscroll-contain {spacing.Padding.Xl} bg-black/50", Surface = $"{positioning.Relative} {display.Flex} {flexbox.Col} {sizing.FullWidth} max-h-[calc(100vh-2rem)] {neutralText.Heading} {neutralSurface.Background}", Header = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Xl} {flexbox.ShrinkNone} {spacing.InteractiveRowPadding} {neutralSurface.Border}", Title = $"{typography.Size.Lg} {typography.Weight.Semibold}", CloseButton = string.Empty, Content = $"overflow-y-auto {spacing.InteractiveRowPadding}", FullScreen = $"{sizing.Full} max-w-none", FullWidth = sizing.FullWidth, SmallWidth = "sm:max-w-lg", MediumWidth = "sm:max-w-xl", LargeWidth = "sm:max-w-3xl" }, Tooltip = new TwTooltipTheme { Wrapper = $"{positioning.Relative} {display.InlineFlex} group", Bubble = $"{positioning.Absolute} z-130 w-max max-w-xs px-2 py-1 {typography.Size.Xs} {typography.Weight.Medium} {neutralText.Heading} hidden group-hover:block group-focus-visible:block group-has-[:focus-visible]:block group-data-[tw-tooltip-open]:block", Dismissed = "!hidden", Top = "bottom-full left-1/2 mb-2 -translate-x-1/2 after:absolute after:inset-x-0 after:top-full after:h-2 after:content-['']", Bottom = "top-full left-1/2 mt-2 -translate-x-1/2 after:absolute after:inset-x-0 after:bottom-full after:h-2 after:content-['']", Left = "end-full top-1/2 me-2 -translate-y-1/2 after:absolute after:inset-y-0 after:start-full after:w-2 after:content-['']", Right = "start-full top-1/2 ms-2 -translate-y-1/2 after:absolute after:inset-y-0 after:end-full after:w-2 after:content-['']", Arrow = $"{positioning.Absolute} size-2 rotate-45 pointer-events-none", ArrowTop = "-bottom-[5px] left-1/2 -translate-x-1/2 border-t-0 border-l-0", ArrowBottom = "-top-[5px] left-1/2 -translate-x-1/2 border-b-0 border-r-0", ArrowLeft = "-end-[5px] top-1/2 -translate-y-1/2 border-b-0 border-s-0 rtl:-rotate-45", ArrowRight = "-start-[5px] top-1/2 -translate-y-1/2 border-t-0 border-e-0 rtl:-rotate-45" } }; return new TwBlazorTheme { Anchor = anchor, Position = positioning, Inset = inset, Display = display, Flexbox = flexbox, Spacing = spacing, Sizing = sizing, Interaction = interaction, Border = border, TextTransform = textTransform, Transition = transition, Typography = typography, Overflow = overflow, Colors = new() { TextColors = text, DarkTextColors = darkText, HoverColors = hoverColors, Transparent = transparentBackground, LightBackground = background, DarkBackground = darkBackground, FocusRingBase = "focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-[oklch(100%_0_0)] dark:focus-visible:ring-offset-[oklch(25.33%_0.016_252.42)]", FocusColors = new() { Primary = "focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400", Accent = "focus-visible:ring-fuchsia-500 dark:focus-visible:ring-fuchsia-400", Success = "focus-visible:ring-green-600 dark:focus-visible:ring-green-400", Danger = "focus-visible:ring-red-500 dark:focus-visible:ring-red-400", Warning = "focus-visible:ring-yellow-500 dark:focus-visible:ring-yellow-400", Info = "focus-visible:ring-blue-500 dark:focus-visible:ring-blue-400", Light = "focus-visible:ring-gray-400 dark:focus-visible:ring-gray-300", Dark = "focus-visible:ring-gray-700 dark:focus-visible:ring-gray-300" }, PeerFocusRingBase = "peer-focus-visible:ring-2 peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-[oklch(100%_0_0)] dark:peer-focus-visible:ring-offset-[oklch(25.33%_0.016_252.42)] forced-colors:peer-focus-visible:outline-2 forced-colors:peer-focus-visible:outline-offset-2 forced-colors:peer-focus-visible:outline-[Highlight]", PeerFocusColors = new() { Primary = "peer-focus-visible:ring-purple-500 dark:peer-focus-visible:ring-purple-400", Accent = "peer-focus-visible:ring-fuchsia-500 dark:peer-focus-visible:ring-fuchsia-400", Success = "peer-focus-visible:ring-green-600 dark:peer-focus-visible:ring-green-400", Danger = "peer-focus-visible:ring-red-500 dark:peer-focus-visible:ring-red-400", Warning = "peer-focus-visible:ring-yellow-500 dark:peer-focus-visible:ring-yellow-400", Info = "peer-focus-visible:ring-blue-500 dark:peer-focus-visible:ring-blue-400", Light = "peer-focus-visible:ring-gray-400 dark:peer-focus-visible:ring-gray-300", Dark = "peer-focus-visible:ring-gray-700 dark:peer-focus-visible:ring-gray-300" }, SurfaceColors = new() { Filled = new() { Primary = $"{background.Medium.Primary} hover:bg-purple-700 active:bg-purple-800 {text.Medium.Light}", Accent = "bg-fuchsia-700 hover:bg-fuchsia-800 active:bg-fuchsia-900 text-gray-100", Success = $"{background.Medium.Success} hover:bg-green-700 active:bg-green-800 text-white", Danger = "bg-red-700 hover:bg-red-800 active:bg-red-900 text-gray-100", Warning = $"{background.Medium.Warning} hover:bg-yellow-600 active:bg-yellow-700 {text.Medium.Dark}", Info = $"{background.Medium.Info} hover:bg-blue-700 active:bg-blue-800 {text.Medium.Light}", Light = $"{background.Medium.Light} hover:bg-gray-50 active:bg-gray-100 {text.Medium.Dark}", Dark = $"{background.Dark.Dark} hover:bg-gray-800 active:bg-gray-700 {text.Medium.Light}", }, Outlined = new() { Primary = $"{text.Medium.Primary} {darkText.Light.Primary} {transparentBackground} {hoverColors.Primary} {borderWidth.Medium} {borderColors.Primary}", Accent = $"{text.Medium.Accent} {darkText.Light.Accent} {transparentBackground} {hoverColors.Accent} {borderWidth.Medium} {borderColors.Accent}", Success = $"{text.Medium.Success} {darkText.Light.Success} {transparentBackground} {hoverColors.Success} {borderWidth.Medium} {borderColors.Success}", Danger = $"{text.Medium.Danger} {darkText.Light.Danger} {transparentBackground} {hoverColors.Danger} {borderWidth.Medium} {borderColors.Danger}", Warning = $"{text.Medium.Warning} {darkText.Light.Warning} {transparentBackground} {hoverColors.Warning} {borderWidth.Medium} {borderColors.Warning}", Info = $"{text.Medium.Info} {darkText.Light.Info} {transparentBackground} {hoverColors.Info} {borderWidth.Medium} {borderColors.Info}", Light = $"{text.Light.Dark} {transparentBackground} {hoverColors.Light} {borderWidth.Medium} {borderColors.Light}", Dark = $"{text.Medium.Dark} {darkText.Light.Dark} {transparentBackground} {hoverColors.Dark} {borderWidth.Medium} {neutralSurface.BorderStrong}", }, Text = new() { Primary = $"{text.Medium.Primary} {darkText.Light.Primary} {transparentBackground} {hoverColors.Primary}", Accent = $"{text.Medium.Accent} {darkText.Light.Accent} {transparentBackground} {hoverColors.Accent}", Success = $"{text.Medium.Success} {darkText.Light.Success} {transparentBackground} {hoverColors.Success}", Danger = $"{text.Medium.Danger} {darkText.Light.Danger} {transparentBackground} {hoverColors.Danger}", Warning = $"{text.Medium.Warning} {darkText.Light.Warning} {transparentBackground} {hoverColors.Warning}", Info = $"{text.Medium.Info} {darkText.Light.Info} {transparentBackground} {hoverColors.Info}", Light = $"{text.Light.Dark} {transparentBackground} {hoverColors.Light}", Dark = $"{text.Dark.Dark} {darkText.Light.Dark} {transparentBackground} {hoverColors.Dark}", }, }, NeutralSurface = neutralSurface, NeutralText = neutralText }, Shadows = shadows, Rounded = rounded, Components = [ overlayTheme, new TwAlertTheme { Colors = new() { Primary = $"{background.Light.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} {borderWidth.AccentEdge} {borderColors.Primary}", Accent = $"{background.Light.Accent} {darkBackground.Dark.Accent} {text.Dark.Accent} {darkText.Light.Accent} {borderWidth.AccentEdge} {borderColors.Accent}", Success = $"{background.Light.Success} {darkBackground.Dark.Success} {text.Dark.Success} {darkText.Light.Success} {borderWidth.AccentEdge} {borderColors.Success}", Danger = $"{background.Light.Danger} {darkBackground.Dark.Danger} {text.Dark.Danger} {darkText.Light.Danger} {borderWidth.AccentEdge} {borderColors.Danger}", Warning = $"{background.Light.Warning} {darkBackground.Dark.Warning} {text.Dark.Warning} {darkText.Light.Warning} {borderWidth.AccentEdge} {borderColors.Warning}", Info = $"{background.Light.Info} {darkBackground.Dark.Info} {text.Dark.Info} {darkText.Light.Info} {borderWidth.AccentEdge} {borderColors.Info}", Light = $"{background.Light.Light} {darkBackground.Dark.Light} {text.Medium.Dark} {darkText.Medium.Dark} {borderWidth.AccentEdge} {borderColors.Light}", Dark = $"{background.Light.Dark} {darkBackground.Dark.Dark} {text.Medium.Dark} {darkText.Light.Dark} {borderWidth.AccentEdge} {borderColors.Dark}", }, TextWrapper = $"{flexbox.Flex1} {sizing.MinWidthNone} {typography.WrapBreakWord}", Padding = "py-4 px-6", DensePadding = "py-2 px-3", StartIconPadding = "pe-2", EndIconPadding = "ps-2", Transition = transition.ColorsSlow, DismissButtonSize = $"{sizing.Icon.Xl} {display.Flex} {anchor.Center} {rounded.Full}", DismissButtonSpacingWithEndIcon = "ms-2", DismissButtonColor = $"text-current {neutralHoverFill} opacity-70 hover:opacity-100 focus-visible:ring-2 focus-visible:ring-current transition-[opacity,background-color] {transition.DurationFast} motion-reduce:transition-none {interaction.FocusOutlineNone}" }, new TwAvatarTheme { Colors = new() { Primary = $"{background.Medium.Primary} {text.Medium.Light}", Accent = "bg-fuchsia-700 text-gray-100", Success = $"{background.Medium.Success} text-white", Danger = "bg-red-700 text-gray-100", Warning = $"{background.Medium.Warning} {text.Medium.Dark}", Info = $"{background.Medium.Info} {text.Medium.Light}", Light = $"{background.Medium.Light} {text.Medium.Dark}", Dark = $"{background.Dark.Dark} {text.Medium.Light}", }, Neutral = $"{neutralTrack} {neutralText.Secondary}", Base = $"{display.InlineFlex} {anchor.Center} {flexbox.ShrinkNone} {overflow.Hidden} {typography.Weight.Semibold} leading-none select-none", Small = $"size-8 {typography.Size.Xs}", Medium = $"size-10 {typography.Size.Sm}", Large = $"size-12 {typography.Size.Base}", ExtraLarge = "size-16 text-xl", Image = $"{sizing.Full} object-cover", Icon = "text-[1.25em]" }, new TwBreadcrumbTheme { List = $"{display.InlineFlex} {flexbox.Wrap} {flexbox.Align.Center} {spacing.Gap.Sm} {typography.Size.Sm}", Item = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Sm} {sizing.MinWidthNone}", Separator = $"{display.InlineFlex} {flexbox.Align.Center} {neutralText.Subtle} select-none", SeparatorIcon = "text-[0.875em] leading-none", Label = $"{display.InlineFlex} {flexbox.Align.Center} gap-1.5 px-1.5 py-1 {rounded.Md} {typography.WrapBreakWord}", Link = $"{typography.Weight.Medium} {neutralText.Muted} hover:text-purple-700 dark:hover:text-purple-300 hover:bg-purple-50 dark:hover:bg-purple-500/15 {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", Current = $"{typography.Weight.Semibold} {neutralText.Heading}", Icon = $"{flexbox.ShrinkNone} leading-none", CurrentIcon = "text-purple-600 dark:text-purple-400" }, new TwButtonTheme { Base = $"{display.InlineFlex} {overflow.Hidden} {anchor.Center} min-h-8 {typography.Size.Sm} {typography.AlignCenter} {transition.ColorsFast} {interaction.FocusOutlineNone} focus-visible:outline-hidden touch-manipulation", Padding = "px-6 py-1", DensePadding = "px-3 py-1", IconButton = $"{display.InlineFlex} {anchor.Center} {sizing.Icon.Xl} {typography.Size.Sm} {rounded.Full} {interaction.FocusOutlineNone}", Typography = typography.Weight.Medium, IconTypography = $"{typography.Size.Lg} leading-none", Uppercase = $"{textTransform.Uppercase} tracking-wide", DisabledCursor = interaction.DisabledCursor, ReadonlyCursor = interaction.ReadonlyCursor, DefaultCursor = interaction.PointerCursor, DisabledFilled = $"bg-[oklch(21%_0.006_285.885)]/15 dark:bg-[oklch(97.807%_0.029_256.847)]/15 {disabledInk} shadow-none {interaction.DisabledCursor}", DisabledOutlined = $"{disabledInk} {transparentBackground} {borderWidth.Thin} border-[oklch(21%_0.006_285.885)]/15 dark:border-[oklch(97.807%_0.029_256.847)]/15 {interaction.DisabledCursor}", DisabledText = $"{disabledInk} {transparentBackground} {interaction.DisabledCursor}" }, new TwCardTheme { Container = "px-6 py-5", Bordered = $"{borderWidth.Thin} {neutralSurface.Border}", Title = $"{typography.Size.Lg} {typography.Weight.Semibold} {typography.WrapBreakWord} {neutralText.Heading}" }, new TwCarouselTheme { Container = $"{positioning.Relative} {overflow.Hidden} {sizing.FullWidth}", Viewport = $"{positioning.Relative} {sizing.Full}", Slide = sizing.Full, SlideContent = sizing.Full, ArrowButton = $"{positioning.Absolute} top-1/2 -translate-y-1/2 z-10 text-lg {shadows.Md}", ArrowButtonStart = "start-2", ArrowButtonEnd = "end-2", PlayPauseButton = $"{positioning.Absolute} top-2 end-2 z-10 text-sm {shadows.Md}", IndicatorContainer = $"{positioning.Absolute} bottom-2 inset-x-0 z-10 w-fit mx-auto {display.Flex} {flexbox.Justify.Center} {flexbox.Align.Center} gap-4 px-4 py-2 {rounded.Full} bg-white/45 dark:bg-black/60 {shadows.Md}", Indicator = $"{positioning.Relative} size-2.5 before:absolute before:-inset-2 before:content-[''] {rounded.Full} {interaction.PointerCursor} {interaction.FocusOutlineNone} {focusRing} focus-visible:ring-offset-2 focus-visible:ring-offset-[oklch(100%_0_0)] dark:focus-visible:ring-offset-[oklch(25.33%_0.016_252.42)] forced-colors:border forced-colors:border-[ButtonText] {transition.ColorsFast}", IndicatorActive = "bg-purple-600 dark:bg-purple-500 forced-colors:bg-[Highlight]", IndicatorInactive = "bg-[oklch(21%_0.006_285.885)]/45 dark:bg-[oklch(97.807%_0.029_256.847)]/50 hover:bg-[oklch(21%_0.006_285.885)]/65 dark:hover:bg-[oklch(97.807%_0.029_256.847)]/70" }, new TwCheckboxTheme { Colors = checkBoxRadioButtonColors, Base = $"peer {borderWidth.Thick} {neutralSurface.BorderStrong} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast} {transition.EaseInOut} {interaction.PointerCursor} appearance-none", Disabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", Hover = $"hover:border-[oklch(21%_0.006_285.885)]/40 dark:hover:border-[oklch(97.807%_0.029_256.847)]/40 {interaction.PointerCursor}", LabelBase = $"{display.Flex} {positioning.Relative} {flexbox.Align.Center} {spacing.Gap.Md} min-h-[24px] {inputLabelText} select-none", LabelInteractiveCursor = interaction.PointerCursor, LabelNonInteractiveCursor = interaction.PointerEventsNone, LabelDisabled = interaction.DisabledOpacity, IconWrapper = $"{positioning.Absolute} opacity-0 peer-checked:opacity-100 translate-x-1/4 rtl:-translate-x-1/4", IndeterminateIconWrapper = $"{positioning.Absolute} translate-x-1/4 rtl:-translate-x-1/4" }, new TwChartTheme { Container = $"{display.Flex} {flexbox.Col} {spacing.Gap.Lg} {sizing.FullWidth} {sizing.MinWidthNone} m-0", Header = $"{display.Flex} {flexbox.Col} gap-0.5", Title = $"{typography.Size.Base} {typography.Weight.Semibold} {neutralText.Heading}", Description = $"{typography.Size.Sm} {neutralText.Muted}", Body = $"{sizing.FullWidth} {sizing.MinWidthNone}", Chart = $"{display.Flex} {flexbox.Col} {spacing.Gap.Lg} {sizing.FullWidth} {sizing.MinWidthNone}", Toolbar = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} gap-x-4 gap-y-2", Legend = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} gap-x-4 gap-y-1 list-none m-0 p-0", LegendItem = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} {typography.Size.Xs} {neutralText.Secondary}", LegendButton = $"{rounded.Sm} {interaction.PointerCursor} {interaction.FocusOutlineNone} {focusRing} {neutralHoverText} {transition.ColorsFast}", LegendItemHidden = "opacity-50 line-through", LegendSwatch = $"size-2.5 {rounded.Sm} {flexbox.ShrinkNone}", TableToggle = spacing.PushEnd, AxisTitle = $"{typography.Size.Xs} {neutralText.Muted}", XAxisTitle = typography.AlignCenter, Frame = sizing.FullWidth, FrameWithYAxis = $"{display.Grid} grid-cols-[auto_minmax(0,1fr)] {sizing.FullWidth}", YAxis = $"{positioning.Relative} max-w-32 pe-2", AxisSizer = $"{display.Flex} {flexbox.Col} h-0 {overflow.Hidden} invisible", Tick = $"{typography.Size.Xs} leading-none tabular-nums whitespace-nowrap {neutralText.Muted}", YTick = $"{positioning.Absolute} end-2 max-w-full truncate", XAxis = $"{positioning.Relative} h-6", XTick = $"{positioning.Absolute} top-2 truncate", Plot = $"{positioning.Relative} {sizing.FullWidth}", Small = "h-40", Medium = "h-64", Large = "h-96", Square = "aspect-square mx-auto", SquareSmall = "max-w-48", SquareMedium = "max-w-72", SquareLarge = "max-w-md", Canvas = $"{positioning.Absolute} inset-0 {sizing.Full} overflow-visible", Rect = $"{positioning.Absolute} forced-color-adjust-none", RoundedTop = "rounded-t-sm", RoundedBottom = "rounded-b-sm", RoundedLeft = "rounded-l-sm", RoundedRight = "rounded-r-sm", RoundedAll = rounded.Sm, SurfaceRing = "ring-1 ring-[oklch(100%_0_0)] dark:ring-[oklch(25.33%_0.016_252.42)]", Dot = $"{positioning.Absolute} {rounded.Full} ring-2 ring-[oklch(100%_0_0)] dark:ring-[oklch(25.33%_0.016_252.42)] forced-color-adjust-none", Glyph = $"{positioning.Absolute} {display.Flex} leading-none", Text = $"{positioning.Absolute} {typography.Size.Xs} leading-none tabular-nums whitespace-nowrap", TextMuted = neutralText.Muted, TextPrimary = neutralText.Heading, TextInverse = "text-white", TextStrong = typography.Weight.Semibold, TextLarge = "text-3xl", TextTruncate = "truncate", FillNone = "fill-none", StrokeHairline = "stroke-1", StrokeNormal = "stroke-2", StrokeThick = "stroke-[6px]", SurfaceStroke = "stroke-2 stroke-[oklch(100%_0_0)] dark:stroke-[oklch(25.33%_0.016_252.42)]", HitWrapper = "min-w-6 min-h-6 hover:z-10 focus-within:z-10", HitWrapperShaped = interaction.PointerEventsNone, HitShape = $"{positioning.Absolute} inset-0 pointer-events-auto", Hit = $"{positioning.Absolute} inset-0 {rounded.Sm} {interaction.FocusOutlineNone} {focusRing} dark:focus-visible:ring-offset-2 dark:focus-visible:ring-offset-[oklch(97.807%_0.029_256.847)]", HitHighlight = $"{positioning.Absolute} inset-0 {rounded.Sm} bg-[oklch(21%_0.006_285.885)]/8 dark:bg-[oklch(97.807%_0.029_256.847)]/10 invisible group-hover:visible group-has-[:focus-visible]:visible group-data-[tw-tooltip-open]:visible {interaction.PointerEventsNone}", Crosshair = $"{positioning.Absolute} inset-y-0 left-1/2 w-px bg-[oklch(21%_0.006_285.885)]/40 dark:bg-[oklch(97.807%_0.029_256.847)]/40 invisible group-hover:visible group-has-[:focus-visible]:visible group-data-[tw-tooltip-open]:visible {interaction.PointerEventsNone}", TooltipTitle = $"{display.Block} {typography.Weight.Semibold}", TooltipRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} mt-1 font-normal", TooltipKey = $"h-0.5 w-3 {rounded.Full} {flexbox.ShrinkNone}", TooltipLabel = neutralText.Secondary, TooltipValue = $"{spacing.PushEnd} ps-3 {typography.Weight.Semibold} tabular-nums", Empty = $"py-8 {typography.AlignCenter} {typography.Size.Sm} {neutralText.Muted}", TableRowHeader = typography.Weight.Medium, Series = [ new() { Background = "bg-purple-600 dark:bg-purple-500", Fill = "fill-purple-600 dark:fill-purple-500", Stroke = "stroke-purple-600 dark:stroke-purple-500", Text = "text-purple-600 dark:text-purple-500" }, new() { Background = "bg-orange-600", Fill = "fill-orange-600", Stroke = "stroke-orange-600", Text = "text-orange-600" }, new() { Background = "bg-teal-600", Fill = "fill-teal-600", Stroke = "stroke-teal-600", Text = "text-teal-600" }, new() { Background = "bg-yellow-700", Fill = "fill-yellow-700", Stroke = "stroke-yellow-700", Text = "text-yellow-700" }, new() { Background = "bg-pink-500", Fill = "fill-pink-500", Stroke = "stroke-pink-500", Text = "text-pink-500" }, new() { Background = "bg-green-600", Fill = "fill-green-600", Stroke = "stroke-green-600", Text = "text-green-600" }, new() { Background = "bg-blue-600 dark:bg-blue-500", Fill = "fill-blue-600 dark:fill-blue-500", Stroke = "stroke-blue-600 dark:stroke-blue-500", Text = "text-blue-600 dark:text-blue-500" }, new() { Background = "bg-red-600 dark:bg-red-500", Fill = "fill-red-600 dark:fill-red-500", Stroke = "stroke-red-600 dark:stroke-red-500", Text = "text-red-600 dark:text-red-500" } ], Positive = new() { Background = "bg-green-600", Fill = "fill-green-600", Stroke = "stroke-green-600", Text = "text-green-600" }, Negative = new() { Background = "bg-red-600 dark:bg-red-500", Fill = "fill-red-600 dark:fill-red-500", Stroke = "stroke-red-600 dark:stroke-red-500", Text = "text-red-600 dark:text-red-500" }, Total = new() { Background = "bg-slate-500 dark:bg-slate-400", Fill = "fill-slate-500 dark:fill-slate-400", Stroke = "stroke-slate-500 dark:stroke-slate-400", Text = "text-slate-500 dark:text-slate-400" }, Sequential = new() { Background = "bg-purple-600 dark:bg-purple-500", Fill = "fill-purple-600 dark:fill-purple-500", Stroke = "stroke-purple-600 dark:stroke-purple-500", Text = "text-purple-600 dark:text-purple-500" }, Track = new() { Background = "bg-[oklch(91%_0_0)] dark:bg-[oklch(34%_0.016_253)]", Fill = "fill-[oklch(91%_0_0)] dark:fill-[oklch(34%_0.016_253)]", Stroke = "stroke-[oklch(91%_0_0)] dark:stroke-[oklch(34%_0.016_253)]", Text = "text-[oklch(91%_0_0)] dark:text-[oklch(34%_0.016_253)]" }, Grid = new() { Background = "bg-[oklch(92%_0_0)] dark:bg-[oklch(32%_0.016_253)]", Fill = "fill-[oklch(92%_0_0)] dark:fill-[oklch(32%_0.016_253)]", Stroke = "stroke-[oklch(92%_0_0)] dark:stroke-[oklch(32%_0.016_253)]", Text = "text-[oklch(92%_0_0)] dark:text-[oklch(32%_0.016_253)]" }, Axis = new() { Background = "bg-[oklch(78%_0_0)] dark:bg-[oklch(48%_0.016_253)]", Fill = "fill-[oklch(78%_0_0)] dark:fill-[oklch(48%_0.016_253)]", Stroke = "stroke-[oklch(78%_0_0)] dark:stroke-[oklch(48%_0.016_253)]", Text = "text-[oklch(78%_0_0)] dark:text-[oklch(48%_0.016_253)]" }, Ink = new() { Background = "bg-[oklch(21%_0.006_285.885)] dark:bg-[oklch(97.807%_0.029_256.847)]", Fill = "fill-[oklch(21%_0.006_285.885)] dark:fill-[oklch(97.807%_0.029_256.847)]", Stroke = "stroke-[oklch(21%_0.006_285.885)] dark:stroke-[oklch(97.807%_0.029_256.847)]", Text = neutralText.Heading } }, new TwChipTheme { Base = $"{display.InlineFlex} {anchor.Center} gap-1.5 {typography.Weight.Medium} {shadows.Sm} {transition.ColorsFast} touch-manipulation", CloseButton = $"{display.Flex} {anchor.Center} {sizing.Icon.Sm} {typography.AlignCenter} {neutralHoverFill} {rounded.Full} {transition.ColorsFast}", ContentButton = $"{display.InlineFlex} {anchor.Center} gap-1.5 bg-transparent text-inherit {rounded.Full} {interaction.PointerCursor} {interaction.FocusOutlineNone} focus-visible:ring-2 focus-visible:ring-current", Sm = "h-5 px-1.5 py-1 text-[10px] leading-none", Md = $"h-6 px-2 py-1 {typography.Size.Xs} leading-none", Lg = $"h-8 px-2.5 py-1.5 {typography.Size.Sm} leading-none" }, new TwCodeBlockTheme { Container = $"{overflow.Hidden} p-1 {neutralSurface.BackgroundSubtle} {borderWidth.Thin} {neutralSurface.Border}", Header = $"px-2 py-1 {typography.Size.Xs} {typography.Weight.Medium} {textTransform.Uppercase} tracking-wide {neutralText.Muted}", Panel = $"{rounded.Md} {typography.Size.Sm} {neutralSurface.Background} {neutralText.Heading} {borderWidth.Thin} {neutralSurface.Border}", Code = $"{rounded.Md} {focusRingInset} {interaction.FocusOutlineNone}", CopyButtonWrapper = $"{neutralText.Muted} {neutralHoverText} {transition.ColorsFast}" }, new TwCollapseTheme { Container = $"tw-collapse {borderWidth.Thin} {neutralSurface.Border}", Trigger = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Md} {sizing.FullWidth} {spacing.InteractiveRowPadding} text-start {typography.Weight.Medium} {neutralText.Heading} {neutralSurface.Hover} {focusRingInset} {transition.ColorsFast} {interaction.FocusOutlineNone} touch-manipulation", Icon = $"{display.Flex} {flexbox.ShrinkNone} {sizing.Icon.Sm} {spacing.PushEnd} {transition.TransformSlow}", IconOpen = "rotate-180", Content = $"{overflow.Hidden} border-t {neutralSurface.Border} {transition.ColorsSlow}" }, new TwColorPickerTheme { Swatch = $"block {flexbox.ShrinkNone} h-7 w-7 {neutralHairlineRing} {shadows.Sm} transition-[box-shadow,opacity] {transition.DurationFast} motion-reduce:transition-none", SwatchDisabled = interaction.DisabledOpacity, SwatchHover = "hover:ring-[oklch(21%_0.006_285.885)]/20 dark:hover:ring-[oklch(97.807%_0.029_256.847)]/25", InputContainer = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md}", DialogPosition = $"{positioning.Fixed} z-120 {spacing.MarginTop.Md}", PreviewSwatch =$"{flexbox.Flex1} {sizing.MinWidthNone} h-6 {rounded.Full} {neutralHairlineRing} {shadows.Sm}", SelectorSquare = $"{positioning.Relative} {overflow.Hidden} {sizing.FullWidth} h-48 {neutralHairlineRing} {focusRing} {interaction.FocusOutlineNone} cursor-crosshair touch-none", SelectorThumb = $"{positioning.Absolute} {sizing.Icon.Sm} {rounded.Full} border-2 border-white ring-1 ring-black/10 {shadows.Lg} {interaction.PointerEventsNone}", SliderTrack = $"{overflow.Hidden} {sizing.FullWidth} h-2.5 {rounded.Full} {neutralHairlineRing} {interaction.PointerEventsNone}", SliderThumb = $"{positioning.Absolute} top-1/2 {sizing.Icon.Sm} {rounded.Full} border-2 border-white ring-1 ring-black/10 {shadows.Lg} {interaction.PointerEventsNone}", AlphaLabel = $"{typography.Size.Xs} {typography.Weight.Medium} {neutralText.Secondary}", ActionBar = $"{display.Flex} {flexbox.Justify.End} {spacing.Gap.Md} pt-1", ControlRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {spacing.Padding.Md} {neutralSurface.BackgroundSubtle}", Body = $"{display.Flex} {flexbox.Col} {spacing.Gap.Lg}", SliderRow = $"{flexbox.Flex1} h-6 {rounded.Full} {focusRing} {interaction.FocusOutlineNone}", HueSliderTouch = "touch-none", InputColumn = flexbox.Flex1, ModeSwitchButton = "shrink-0 tracking-wide", AlphaReadoutAlign = "text-end" }, new TwDatePickerTheme { Header = $"{typography.AlignCenter} {typography.Weight.Medium} {overlayTheme.Popover.Background} {rounded.RoundedTop.Lg} border-b {neutralSurface.BorderStrong}", WeekdaysHeader = $"{display.Flex} {anchor.Center} h-8 {typography.Size.Xs} font-normal {neutralText.Muted}", Base = $"{positioning.Fixed} z-120 {flexbox.Row} md:flex-row {flexbox.Align.Center} mt-1 px-2 pb-2 {typography.AlignCenter} {typography.Size.Sm} {typography.Weight.Medium} {transition.ColorsFast} {interaction.PointerCursor}", ActiveClass = $"{neutralTrack} {neutralText.Heading} {typography.Weight.Semibold}", SelectedClass = $"bg-purple-600 hover:bg-purple-700 text-white {typography.Weight.Semibold}", HoverClass = neutralHoverFill, ButtonClass = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Center} h-8 {sizing.FullWidth} {spacing.Padding.Md} tabular-nums {focusRingInset} {interaction.FocusOutlineNone} {transition.ColorsFast}", RangeClass = "bg-purple-100 text-purple-900 dark:bg-purple-500/20 dark:text-purple-100", RangeMonthCaptionClass = $"mt-2 {typography.AlignCenter} {typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Heading}", PrevMonthClass = neutralText.Subtle, DefaultFormat = "dd/MM/yyyy", DefaultDateTimeFormat = "dd/MM/yyyy HH:mm", DefaultDateTimeFormat12Hour = "dd/MM/yyyy hh:mm tt", DefaultRangeSeparator = " - ", IconTriggerWrapper = $"{positioning.Absolute} {inset.Top} {inset.Start} {display.Flex} {flexbox.Align.Center} {spacing.PaddingStart.Lg} {interaction.PointerCursor}", IconGlyph = $"{sizing.Icon.Md} {neutralText.Subtle}", TextfieldPadding = "ps-10 pe-3", NativeInputAppearance = "appearance-none !flex items-center [&::-webkit-date-and-time-value]:min-h-0 [&::-webkit-date-and-time-value]:text-start [&::-webkit-datetime-edit]:p-0", PanelWidth = "w-67", HeaderControls = $"{display.Flex} {flexbox.Justify.Between} {flexbox.Align.Center} h-9", Body = display.Flex, YearsGrid = $"{display.Grid} grid-cols-5 justify-items-stretch {spacing.Gap.Sm} {sizing.FullWidth} {spacing.MarginTop.Md}", MonthsGrid = $"{display.Grid} grid-cols-6 justify-items-stretch {spacing.Gap.Sm} {sizing.FullWidth} {spacing.MarginTop.Md}", DualMonthLayout = $"{display.Flex} {flexbox.Col} md:flex-row {spacing.Gap.Xl}", DualMonthColumn = "md:flex-1 md:min-w-0", DayGrid = $"{sizing.FullWidth} border-collapse", DayHeaderCellPadding = "p-0", DayAbbreviation = "no-underline", RangeStageTabsContainer = $"{display.Flex} {spacing.Gap.Sm} {spacing.Padding.Sm} {rounded.Lg} {neutralTrack} {spacing.MarginBottom.Md}", RangeStageTabInactive = neutralText.Subtle, PanelMaxHeight = "overflow-y-auto max-h-[calc(100vh-2rem)]", PanelMaxWidth = "overflow-x-auto max-w-[calc(100vw-2rem)]", DualMonthPanelWidth = "md:w-138", StageTabBase = $"{flexbox.Flex1} py-1.5 {typography.Size.Sm} {typography.Weight.Medium} {typography.AlignCenter} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", StageTabActive = $"bg-white dark:bg-[oklch(34%_0.018_253)] {neutralText.Heading} {shadows.Sm}", HeaderNavButton = "py-2 px-4 text-xl" }, new TwFileUploadTheme { IconSpacing = "me-2", FileList = $"{typography.Size.Sm} {neutralText.Secondary}", ChipTextColor = "dark:text-white", FocusRing = "has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-purple-500 dark:has-[:focus-visible]:ring-purple-400 has-[:focus-visible]:ring-offset-2 has-[:focus-visible]:ring-offset-[oklch(100%_0_0)] dark:has-[:focus-visible]:ring-offset-[oklch(25.33%_0.016_252.42)] forced-colors:has-[:focus-visible]:outline-2 forced-colors:has-[:focus-visible]:outline-offset-2 forced-colors:has-[:focus-visible]:outline-[Highlight]" }, new TwFooterTheme { Footer = $"{sizing.FullWidth} {neutralSurface.BackgroundSubtle} {neutralText.Secondary} border-t {neutralSurface.Border}", Container = "mx-auto w-full max-w-7xl px-6 py-10", Brand = "mb-8", Sections = $"{display.Grid} grid-cols-2 gap-8 md:grid-cols-4", Section = sizing.MinWidthNone, SectionTitle = $"{typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Heading}", LinkList = $"mt-3 {display.Flex} {flexbox.Col} {spacing.Gap.Md} list-none m-0 p-0", Link = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} {typography.Size.Sm} {rounded.Sm} underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current", Content = "mt-8 first:mt-0", Bottom = $"mt-8 {display.Flex} {flexbox.Wrap} {flexbox.Align.Center} {flexbox.Justify.Between} gap-x-6 gap-y-3 border-t border-current/15 pt-6 first:mt-0 first:border-t-0 first:pt-0 {typography.Size.Xs}", Copyright = "m-0 max-w-3xl", BottomLinks = $"{display.Flex} {flexbox.Wrap} gap-x-4 gap-y-2 list-none m-0 p-0" }, new TwIconTheme { Colors = new() { Primary = "text-purple-600 dark:text-purple-400", Accent = "text-fuchsia-600 dark:text-fuchsia-400", Success = "text-green-600 dark:text-green-400", Danger = "text-red-600 dark:text-red-400", Warning = "text-[oklch(65%_0.15_80)] dark:text-yellow-400", Info = "text-blue-600 dark:text-blue-400", Light = "text-gray-100 dark:text-white", Dark = "text-gray-950 dark:text-gray-950", }, HoverBackground = "hover:bg-current/10 dark:hover:bg-current/15", Pulse = "relative tw-icon-pulse" }, new TwLinkTheme { Default = $"underline-offset-2 hover:underline {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}" }, new TwGroupsTheme { Gap = spacing.Gap.Md, FieldsetBase = "p-0 m-0 border-none", HorizontalLayout = $"{display.Flex} {flexbox.Row} {flexbox.Wrap}", VerticalLayout = $"{display.Flex} {flexbox.Col}", CheckboxGroupDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", RadioGroupDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", ButtonGroupBase = display.InlineFlex, ButtonGroupVertical = flexbox.Col, ButtonGroupHorizontal = $"{flexbox.Row} {flexbox.Wrap}", ButtonGroupFullWidth = sizing.FullWidth, ButtonGroupFullWidthRow = "[&>*]:flex-1", ChipGroupBase = $"{display.Flex} {flexbox.Wrap}", ChipGroupAlignStart = flexbox.Justify.Start, ChipGroupAlignCenter = flexbox.Justify.Center, ChipGroupAlignEnd = flexbox.Justify.End }, new TwInputTheme { DefaultInputVariant = InputVariant.Outlined, TextfieldBase = $"{display.Block} {sizing.FullWidth} {sizing.MinWidthNone} max-w-full {neutralText.Heading} placeholder:text-[oklch(21%_0.006_285.885)]/65 dark:placeholder:text-[oklch(97.807%_0.029_256.847)]/65 {transition.ColorsFast} {transition.EaseInOut} {interaction.FocusOutlineNone}", SelectBase = $"{display.Block} {sizing.FullWidth} pe-10 {neutralText.Heading} bg-[url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2020%2020%22%3E%3Cpath%20stroke%3D%22%236b7280%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%221.5%22%20d%3D%22m6%208%204%204%204-4%22%2F%3E%3C%2Fsvg%3E')] bg-[length:1.5em_1.5em] bg-[right_0.5rem_center] rtl:bg-[left_0.5rem_center] bg-no-repeat {transition.ColorsFast} appearance-none {interaction.FocusOutlineNone} supports-[appearance:base-select]:[appearance:base-select] supports-[appearance:base-select]:flex supports-[appearance:base-select]:items-center [&::picker(select)]:[appearance:base-select] [&::picker-icon]:hidden [&::picker(select)]:border-[oklch(21%_0.006_285.885)]/25 dark:[&::picker(select)]:border-[oklch(97.807%_0.029_256.847)]/20 [&::picker(select)]:bg-[oklch(100%_0_0)] dark:[&::picker(select)]:bg-[oklch(40%_0.016_253)]", Size = $"{inputHeight} {typography.Size.Base}", DenseSize = $"{inputDenseHeight} {typography.Size.Sm}", MultilineSize = $"[--textarea-py:0.75rem] py-(--textarea-py) {typography.Size.Base}", MultilineDenseSize = $"[--textarea-py:0.5rem] py-(--textarea-py) {typography.Size.Sm}", MultilineResize = "resize-y", MultilineAutoGrow = "field-sizing-content resize-none", FieldWrapper = positioning.Relative, FieldStartContent = $"{positioning.Absolute} top-0 start-0 {display.Flex} {flexbox.Align.Center} {interaction.PointerEventsNone}", FieldEndContent = $"{positioning.Absolute} top-0 end-0 {display.Flex} {flexbox.Align.Stretch} gap-1 py-px pe-px", ClearablePadding = "pe-10", ClearButton = $"{display.InlineFlex} w-8 {flexbox.Align.Center} {flexbox.Justify.Center} {flexbox.ShrinkNone} {rounded.Md} {neutralText.Secondary} {neutralHoverText} {neutralHoverFill} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone} disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent forced-colors:text-[ButtonText] forced-colors:disabled:text-[GrayText]", ClearButtonIcon = $"{typography.Size.Sm} leading-none", SelectOption = $"{spacing.Padding.Lg} dark:bg-gray-800 dark:text-white supports-[appearance:base-select]:[padding-inline:revert] supports-[appearance:base-select]:py-2 supports-[appearance:base-select]:bg-transparent dark:supports-[appearance:base-select]:bg-transparent supports-[appearance:base-select]:hover:bg-[oklch(97%_0_0)] dark:supports-[appearance:base-select]:hover:bg-[oklch(34%_0.018_253)] supports-[appearance:base-select]:checked:bg-purple-50 supports-[appearance:base-select]:checked:text-purple-700 dark:supports-[appearance:base-select]:checked:bg-purple-500/20 dark:supports-[appearance:base-select]:checked:text-purple-300", SelectNativeBackground = "!bg-white dark:!bg-gray-800", SelectDefaultPadding = "px-3", SelectReadOnlyBackground = "!bg-none", SelectMultiTriggerLayout = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} {spacing.Gap.Sm} min-h-10 py-0.5 {typography.Size.Base}", SelectNativeMultiOverlay = $"{positioning.Absolute} inset-0 {sizing.Full} m-0 opacity-0 {interaction.PointerCursor} {interaction.FocusOutlineNone} touch-manipulation", SelectMultiOpenButton = $"{flexbox.Flex1} min-w-[2rem] min-h-8 truncate text-start bg-transparent border-0 {interaction.FocusOutlineNone}", SelectPanelPosition = $"{positioning.Fixed} z-120 {spacing.MarginTop.Md}", SelectPanelSurface = $"overflow-y-auto max-h-64 {spacing.Padding.Sm}", SelectPanelItemText = "[&_label]:!text-[oklch(21%_0.006_285.885)] dark:[&_label]:!text-[oklch(97.807%_0.029_256.847)] [&_fieldset]:gap-0 [&_label]:w-full [&_label]:gap-2 [&_label]:px-2 [&_label]:py-2 [&_label]:text-base [&_input]:sr-only [&_label>span]:hidden [&_label::before]:content-['✓'] [&_label::before]:invisible [&_label::before]:w-4 [&_label::before]:shrink-0 [&_label::before]:text-center [&_label:has(input:checked)::before]:visible [&_label:hover]:bg-[oklch(97%_0_0)] dark:[&_label:hover]:bg-[oklch(34%_0.018_253)] [&_label:has(input:checked)]:bg-purple-50 dark:[&_label:has(input:checked)]:bg-purple-500/20 [&_label:has(input:checked)]:!text-purple-700 dark:[&_label:has(input:checked)]:!text-purple-300 [&_label:has(input:focus-visible)]:ring-2 [&_label:has(input:focus-visible)]:ring-inset [&_label:has(input:focus-visible)]:ring-purple-500 dark:[&_label:has(input:focus-visible)]:ring-purple-400", SelectCustomTrigger = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Md} {sizing.FullWidth} {sizing.MinWidthNone} text-start {neutralText.Heading} {transition.ColorsFast} {interaction.FocusOutlineNone} {interaction.PointerCursor}", SelectCustomPlaceholder = $"{neutralText.Muted}", SelectCustomChevron = $"{display.Flex} {anchor.Center} {sizing.Icon.Sm} {flexbox.ShrinkNone} leading-none {neutralText.Muted} {transition.TransformFast}", SelectCustomChevronOpen = "rotate-180", SelectCustomListbox = $"{display.Flex} {flexbox.Col} gap-0.5 {interaction.FocusOutlineNone}", SelectCustomOption = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Md} {rounded.Md} px-2 py-2 {typography.Size.Sm} {neutralText.Heading} {interaction.PointerCursor} select-none data-[active=true]:bg-[oklch(95%_0_0)] dark:data-[active=true]:bg-[oklch(48%_0.016_253)] data-[active=true]:outline-2 data-[active=true]:-outline-offset-2 data-[active=true]:outline-purple-600 dark:data-[active=true]:outline-purple-300 aria-selected:font-semibold", SelectMultiTriggerBase = $"{positioning.Relative} {sizing.FullWidth} {sizing.MinWidthNone} text-start pe-10 {neutralText.Heading} {transition.ColorsFast} {interaction.FocusOutlineNone} {interaction.PointerCursor}", SelectMultiChipsPadding = "ps-0.75", SelectMultiChevron = $"{positioning.Absolute} end-3 top-1/2 -translate-y-1/2 {display.Flex} {sizing.Icon.Sm} leading-none {neutralText.Muted} {transition.TransformFast} {interaction.PointerEventsNone}", SelectCustomCheck = $"{sizing.Icon.Sm} {flexbox.ShrinkNone} text-purple-600 dark:text-purple-300", InputLegendBase = $"mb-3 {typography.Size.Base} {typography.Weight.Medium} {neutralText.Secondary}", LabelBase = $"{display.Block} mb-2 {inputLabelText}", OutlinedBorder = $"{borderWidth.Thin} {neutralSurface.BorderStrong}", FilledBorder = $"border-b {neutralSurface.BorderStrong}", FocusBorder = "focus:border-purple-600 dark:focus:border-purple-400 focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-400", FocusVisibleBorder = "focus-visible:border-purple-600 dark:focus-visible:border-purple-400 focus-visible:ring-2 focus-visible:ring-purple-500 dark:focus-visible:ring-purple-400", FocusWithinBorder = "has-[:focus-visible]:border-purple-600 dark:has-[:focus-visible]:border-purple-400 has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-purple-500 dark:has-[:focus-visible]:ring-purple-400", FilledBackgroundColor = neutralSurface.Elevated, ErrorMessage = $"{spacing.MarginTop.Sm} {typography.Size.Xs} {text.Medium.Danger} {darkText.Medium.Danger}" }, new TwNumericTheme { Adornment = $"self-center whitespace-nowrap select-none {neutralText.Secondary}", Button = $"{display.InlineFlex} {flexbox.Align.Center} {flexbox.Justify.Center} {flexbox.ShrinkNone} {rounded.Md} {neutralText.Secondary} {neutralHoverText} {neutralHoverFill} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone} disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent forced-colors:text-[ButtonText] forced-colors:disabled:text-[GrayText]", ButtonIcon = $"{typography.Size.Sm} leading-none" }, new TwMenuTheme { Root = $"{positioning.Relative} {display.InlineFlex}", Panel = $"z-50 min-w-48 max-w-xs overflow-y-auto {rounded.Lg} {borderWidth.Thin} {neutralSurface.Border} {neutralSurface.Background} shadow-lg py-1 {interaction.FocusOutlineNone}", Item = $"{display.Flex} {sizing.FullWidth} {flexbox.Align.Center} {spacing.Gap.Sm} px-3 py-2 text-start {typography.Size.Sm} {neutralText.Heading} {neutralRowHover} focus-visible:bg-[oklch(21%_0.006_285.885)]/5 dark:focus-visible:bg-[oklch(97.807%_0.029_256.847)]/8 {interaction.PointerCursor} {transition.ColorsFast} {interaction.FocusOutlineNone} {focusRingInset}", ItemDisabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", ItemIcon = $"{typography.Size.Base} {flexbox.ShrinkNone} {neutralText.Subtle}", CheckIcon = $"{typography.Size.Base} {flexbox.ShrinkNone} text-purple-600 dark:text-purple-300", CheckIconHidden = "invisible", Divider = $"my-1 border-t {neutralSurface.Border}", GroupLabel = $"px-3 pt-2 pb-1 {typography.Size.Xs} {typography.Weight.Semibold} {neutralText.Muted}" }, new TwOnThisPageTheme { Title = $"{spacing.MarginBottom.Lg} {typography.Weight.Semibold} {neutralText.Heading}", List = $"border-s {neutralSurface.Border}", Link = $"{display.Block} -ms-px py-1 ps-4 border-s border-transparent {neutralText.Muted} {neutralHoverText} hover:border-[oklch(21%_0.006_285.885)]/45 dark:hover:border-[oklch(97.807%_0.029_256.847)]/45 {transition.ColorsFast} {focusRingInset} {interaction.FocusOutlineNone}", LinkCurrent = $"aria-[current=location]:font-medium aria-[current=location]:border-purple-600 dark:aria-[current=location]:border-purple-400 aria-[current=location]:text-[oklch(21%_0.006_285.885)] dark:aria-[current=location]:text-[oklch(97.807%_0.029_256.847)] forced-colors:aria-[current=location]:border-[Highlight]" }, new TwPaginationTheme { List = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm}", Base = $"{display.Flex} {anchor.Center} tabular-nums select-none {transition.ColorsFast} {focusRingInset} {interaction.FocusOutlineNone}", Size = $"{inputHeight} min-w-10 px-3 {typography.Size.Sm}", DenseSize = $"{inputDenseHeight} min-w-8 px-2 {typography.Size.Sm}", ActiveButton = $"{typography.Weight.Semibold} bg-purple-50 text-purple-700 ring-1 ring-inset ring-purple-600/20 dark:bg-purple-500/20 dark:text-purple-300 dark:ring-purple-400/30 forced-colors:outline forced-colors:outline-2 forced-colors:-outline-offset-2 forced-colors:outline-[Highlight] {interaction.PointerCursor}", Buttons = $"{neutralText.Secondary} {neutralHoverFill} {neutralHoverText} {interaction.PointerCursor}", DisabledButton = "text-[oklch(21%_0.006_285.885)]/40 dark:text-[oklch(97.807%_0.029_256.847)]/40 cursor-not-allowed" }, new TwPickListTheme { Container = $"{display.Flex} {flexbox.Align.Start} {spacing.Gap.Lg}", Column = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm} {flexbox.Flex1} {sizing.MinWidthNone}", ColumnHeader = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {spacing.Gap.Sm} min-h-8", Label = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Heading}", ReorderButtons = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm}", ReorderButton = $"{neutralText.Muted} {neutralHoverFill} {neutralHoverText} {transition.ColorsFast} aria-disabled:text-[oklch(21%_0.006_285.885)]/40 dark:aria-disabled:text-[oklch(97.807%_0.029_256.847)]/40 aria-disabled:hover:bg-transparent dark:aria-disabled:hover:bg-transparent aria-disabled:cursor-not-allowed", TransferButton = $"{borderWidth.Thin} {neutralSurface.BorderStrong} {neutralText.Secondary} {neutralHoverFill} {neutralHoverText} {transition.ColorsFast} aria-disabled:text-[oklch(21%_0.006_285.885)]/40 dark:aria-disabled:text-[oklch(97.807%_0.029_256.847)]/40 aria-disabled:border-[oklch(21%_0.006_285.885)]/20 dark:aria-disabled:border-[oklch(97.807%_0.029_256.847)]/20 aria-disabled:hover:bg-transparent dark:aria-disabled:hover:bg-transparent aria-disabled:cursor-not-allowed", TransferButtonColumn = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center} {flexbox.Justify.Center} {flexbox.AlignSelf.Center} {spacing.Gap.Md}", ListBox = $"overflow-y-auto {sizing.FullWidth} h-64 {spacing.Padding.Sm} {neutralSurface.Background} {borderWidth.Thin} {neutralSurface.BorderStrong}", ListBoxDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", Item = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {rounded.Md} px-3 py-2 {typography.Size.Sm} {neutralText.Heading} {neutralRowHover} aria-selected:bg-purple-50 aria-selected:text-purple-700 aria-selected:hover:bg-purple-100 dark:aria-selected:bg-purple-500/20 dark:aria-selected:text-purple-300 dark:aria-selected:hover:bg-purple-500/30 {focusRingInset} {transition.ColorsFast} {interaction.PointerCursor} select-none {interaction.FocusOutlineNone}", ItemSelected = typography.Weight.Medium, EmptyState = $"px-3 py-8 {typography.AlignCenter} {typography.Size.Sm} {neutralText.Subtle}" }, new TwProgressTheme { Colors = new() { Primary = "[&::-webkit-progress-value]:bg-purple-600 dark:[&::-webkit-progress-value]:bg-purple-500 [&::-moz-progress-bar]:bg-purple-600 dark:[&::-moz-progress-bar]:bg-purple-500", Accent = "[&::-webkit-progress-value]:bg-fuchsia-600 dark:[&::-webkit-progress-value]:bg-fuchsia-500 [&::-moz-progress-bar]:bg-fuchsia-600 dark:[&::-moz-progress-bar]:bg-fuchsia-500", Success = "[&::-webkit-progress-value]:bg-green-600 dark:[&::-webkit-progress-value]:bg-green-500 [&::-moz-progress-bar]:bg-green-600 dark:[&::-moz-progress-bar]:bg-green-500", Danger = "[&::-webkit-progress-value]:bg-red-600 dark:[&::-webkit-progress-value]:bg-red-500 [&::-moz-progress-bar]:bg-red-600 dark:[&::-moz-progress-bar]:bg-red-500", Warning = "[&::-webkit-progress-value]:bg-yellow-500 dark:[&::-webkit-progress-value]:bg-yellow-400 [&::-moz-progress-bar]:bg-yellow-500 dark:[&::-moz-progress-bar]:bg-yellow-400", Info = "[&::-webkit-progress-value]:bg-blue-600 dark:[&::-webkit-progress-value]:bg-blue-500 [&::-moz-progress-bar]:bg-blue-600 dark:[&::-moz-progress-bar]:bg-blue-500", Light = "[&::-webkit-progress-value]:bg-gray-400 dark:[&::-webkit-progress-value]:bg-gray-300 [&::-moz-progress-bar]:bg-gray-400 dark:[&::-moz-progress-bar]:bg-gray-300", Dark = "[&::-webkit-progress-value]:bg-gray-900 dark:[&::-webkit-progress-value]:bg-gray-100 [&::-moz-progress-bar]:bg-gray-900 dark:[&::-moz-progress-bar]:bg-gray-100" }, Base = $"{display.Block} {overflow.Hidden} {sizing.FullWidth} {sizing.MinWidthNone} tabular-nums {neutralTrackStrong} {rounded.Full} {borderWidth.Thin} {neutralSurface.BorderStrong} forced-colors:[&::-webkit-progress-value]:bg-[Highlight] forced-colors:[&::-moz-progress-bar]:bg-[Highlight] indeterminate:animate-pulse indeterminate:motion-reduce:animate-none appearance-none [&::-webkit-progress-bar]:rounded-full [&::-webkit-progress-bar]:bg-transparent [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:transition-[width] [&::-webkit-progress-value]:{transition.DurationSlow} [&::-moz-progress-bar]:rounded-full [&::-moz-progress-bar]:transition-[width] [&::-moz-progress-bar]:{transition.DurationSlow}", Small = "h-1.5", Medium = "h-2.5", Large = "h-4", Wrapper = $"{positioning.Relative} {display.Block}", Animated = $"{positioning.Absolute} inset-y-0 start-0 {overflow.Hidden} {rounded.Full} {interaction.PointerEventsNone} transition-[width] {transition.DurationSlow} tw-wave [--tw-wave-color:rgb(255_255_255/0.7)] dark:[--tw-wave-color:rgb(255_255_255/0.4)]" }, new TwTabTheme { TabBase = $"{positioning.Relative} {display.InlineFlex} {anchor.Center} {typography.Weight.Medium} {typography.Size.Sm} {transition.ColorsFast} {focusRingInset} {interaction.FocusOutlineNone} touch-manipulation", TabPadding = "px-6 py-3", TabDensePadding = "px-4 py-2", ActiveIndicator = "after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-current forced-colors:after:bg-[Highlight] after:scale-x-100 after:transition-transform after:duration-200 after:motion-reduce:transition-none", InactiveIndicator = $"{neutralText.Muted} {neutralHoverText} {neutralRowHover} after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-current after:scale-x-0 after:transition-transform after:duration-200 after:motion-reduce:transition-none", DisabledTab = $"{neutralText.Muted} {interaction.DisabledOpacity} {interaction.DisabledCursor}", TabListContainer = $"{display.Flex} {flexbox.Wrap} {overflow.Hidden} {borderWidth.Thin} {neutralSurface.Border}", PanelContainer = $"px-6 py-5 border-x border-b {neutralSurface.Border} {focusRingInset} {interaction.FocusOutlineNone}", Background = neutralSurface.Background, }, new TwBarcodeTheme { Base = $"{display.InlineFlex} {flexbox.Col} {flexbox.Align.Center} {flexbox.ShrinkNone} max-w-full forced-color-adjust-none", Background = "bg-white", Foreground = "text-black", Text = $"font-mono {typography.Size.Xs} tracking-widest pb-1", Small = "h-10 max-w-full", Medium = "h-16 max-w-full", Large = "h-24 max-w-full" }, new TwQrCodeTheme { Base = $"{display.InlineBlock} {flexbox.ShrinkNone} forced-color-adjust-none", Background = "bg-white dark:bg-transparent", Foreground = "text-black dark:text-white", Small = "size-24", Medium = "size-40", Large = "size-56", ExtraLarge = "size-72" }, new TwSkeletonTheme { Base = $"{display.Block} {positioning.Relative} {overflow.Hidden} {neutralTrack}", Text = $"{sizing.FullWidth} h-4", Circle = "size-12", Rectangle = $"{sizing.FullWidth} h-24", MeasuringWrapper = "invisible", Pulse = "animate-pulse motion-reduce:animate-none", Wave = "tw-wave" }, new TwSidebarTheme { SkipLink = "focus:not-sr-only focus:absolute focus:top-2 focus:start-2 focus:z-140 focus:px-3 focus:py-2 focus:text-sm focus:font-medium focus:bg-[oklch(100%_0_0)] dark:focus:bg-[oklch(40%_0.016_253)] focus:text-[oklch(21%_0.006_285.885)] dark:focus:text-[oklch(97.807%_0.029_256.847)] focus:rounded focus:shadow-lg", MobileOverlay = "inset-0 z-90 lg:hidden bg-black/50", DrawerCloseButton = "lg:hidden absolute top-2 end-2 text-lg", MobileClosed = "-translate-x-full rtl:translate-x-full", MobileOpen = "lg:relative translate-x-0", NavigationList = "overflow-y-auto pb-6", NavbarFixedInset = "left-0 right-0", NavbarNavigationResponsive = "lg:flex lg:flex-1 lg:flex-row lg:w-auto lg:p-0 lg:bg-transparent lg:shadow-none", NavbarNavigationExpanded = "flex flex-1", NavigationItemToggleLabel = "me-auto text-start", NavigationItemToggleIcon = "transition-transform", Navbar = $"{display.Flex} z-40 {flexbox.Align.Center} {flexbox.ShrinkNone} {sizing.FullWidth} min-h-14 px-4 py-2 {neutralSurface.Background} {neutralText.Heading} border-b {neutralSurface.Border}", NavbarContent = $"{display.Flex} {flexbox.Wrap} {flexbox.Align.Center} {spacing.Gap.Xl} {sizing.FullWidth}", NavbarBrand = flexbox.ShrinkNone, NavbarNavigation = $"{flexbox.Align.Center} {spacing.Gap.Md}", NavbarActions = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {spacing.PushEnd}", NavbarActionsCollapsible = "max-lg:ms-0 max-lg:mt-2 max-lg:flex-wrap max-lg:justify-center max-lg:border-t max-lg:border-current/15 max-lg:pt-3", NavbarToggle = $"lg:hidden {spacing.PushEnd} -me-2 size-11 {flexbox.ShrinkNone} text-2xl", NavbarToggleIcon = $"text-xl {neutralText.Secondary} {neutralHoverText} {transition.ColorsFast}", NavbarLink = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} px-3 py-1.5 {typography.Size.Sm} {typography.Weight.Medium} {neutralText.Secondary} {neutralHoverFill} {neutralHoverText} {rounded.Md} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", NavbarLinkCollapsible = "max-lg:w-full max-lg:min-h-11 max-lg:px-3 max-lg:text-base", NavbarLinkActive = $"{neutralTrack} {neutralText.Heading}", NavbarMobileMenu = "max-lg:basis-full max-lg:-mx-4 max-lg:-mt-2 max-lg:-mb-2 max-lg:max-h-[calc(100dvh-3.5rem)] max-lg:overflow-y-auto max-lg:overscroll-contain max-lg:items-stretch max-lg:gap-1 max-lg:border-t max-lg:border-current/15 max-lg:px-2 max-lg:py-2 max-lg:[&>a]:flex max-lg:[&>a]:min-h-11 max-lg:[&>a]:w-full max-lg:[&>a]:items-center max-lg:[&>a]:px-3 max-lg:[&>a]:text-base", Sidebar = $"z-100 overflow-auto scrollbar-gutter-stable overscroll-contain {flexbox.ShrinkNone} h-dvh w-64 {spacing.Padding.Xl} {neutralSurface.Background} border-e {neutralSurface.Border} {transition.TransformFast} {transition.EaseInOut}", NavigationItemBase = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md} {sizing.MinWidthNone} px-3 py-2 {typography.Size.Sm} {neutralText.Secondary} {neutralSurface.Hover} {focusRingInset} {transition.ColorsFast} {interaction.FocusOutlineNone} {interaction.PointerCursor}", NavigationItemActive = $"{neutralTrack} {neutralText.Heading}", NavigationItemCurrent = $"{positioning.Relative} {overflow.Hidden} before:absolute before:inset-y-0 before:start-0 before:w-0.5 before:bg-linear-to-b before:from-purple-600 before:to-fuchsia-500 forced-colors:before:bg-[Highlight]", NavigationItemParent = typography.Weight.Semibold, NavigationItemIcon = flexbox.ShrinkNone, NavigationItemContent = $"{display.InlineFlex} {flexbox.Align.Center} {flexbox.ShrinkNone} {spacing.PushEnd}", NavigationDropdownContainer = neutralSurface.BackgroundSubtle, NavigationItemActiveLevelDeep = $"border-s-2 {border.Neutral.Strong}", NavigationDropdownContainerDeep = string.Empty, NavigationGroupRailDeep = $"border-s-2 {border.Neutral.Strong}", MainContent = $"overflow-y-auto scrollbar-gutter-stable start-0 {flexbox.Flex1} {sizing.FullWidth} {focusRingInset} {interaction.FocusOutlineNone} transition-[margin] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut}", MainContentRoot = $"{display.Flex} overflow-x-hidden {flexbox.Col} h-dvh {sizing.FullWidth} {transparentBackground} {neutralSurface.Body} {neutralText.Heading} transition-[margin] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut}" }, new TwTreeListTheme { Container = $"{display.Flex} {flexbox.Col} {typography.Size.Sm}", Group = $"{display.Flex} {flexbox.Col} gap-0.5 mt-0.5 ms-3 ps-2 border-s {neutralSurface.Border}", Row = $"group/row {display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm} {sizing.MinWidthNone} {rounded.Md} px-2 py-1.5 {typography.Size.Sm} {neutralText.Heading} {neutralRowHover} [li:focus-visible>&]:ring-inset [li:focus-visible>&]:ring-2 [li:focus-visible>&]:ring-purple-500 dark:[li:focus-visible>&]:ring-purple-400 forced-colors:[li:focus-visible>&]:outline-2 forced-colors:[li:focus-visible>&]:-outline-offset-2 forced-colors:[li:focus-visible>&]:outline-[Highlight] {transition.ColorsFast} {interaction.PointerCursor}", RowDisabled = $"{interaction.DisabledOpacity} {interaction.PointerEventsNone}", ToggleSlot = $"{display.InlineFlex} {flexbox.ShrinkNone} {flexbox.Align.Center} {flexbox.Justify.Center} size-6", ToggleIcon = $"{display.InlineFlex} {flexbox.ShrinkNone} {flexbox.Align.Center} {flexbox.Justify.Center} size-6 {rounded.Full} {neutralText.Muted} {neutralHoverFill} {neutralHoverText} transition-[transform,background-color,color] {transition.DurationFast} motion-reduce:transition-none", ToggleIconOpen = "rotate-90 rtl:-rotate-90", Label = "truncate", ItemIcon = $"{display.InlineFlex} {flexbox.ShrinkNone} {flexbox.Align.Center} {flexbox.Justify.Center} {sizing.Icon.Sm} {neutralText.Muted}", CheckboxWrapper = $"{display.InlineFlex} {flexbox.Align.Center} {flexbox.ShrinkNone} h-4", ItemOutline = "outline-hidden" }, new TwRadioButtonTheme { Colors = checkBoxRadioButtonColors, Base = $"peer {sizing.Icon.Md} {rounded.Full} {borderWidth.Thick} {neutralSurface.BorderStrong} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast} {transition.EaseInOut} {interaction.PointerCursor} appearance-none", Disabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", Hover = $"hover:border-[oklch(21%_0.006_285.885)]/40 dark:hover:border-[oklch(97.807%_0.029_256.847)]/40 {interaction.PointerCursor}", LabelBase = $"{display.Flex} {positioning.Relative} {flexbox.Align.Center} {spacing.Gap.Md} min-h-[24px] {inputLabelText} select-none", LabelInteractiveCursor = interaction.PointerCursor, LabelNonInteractiveCursor = interaction.PointerEventsNone, LabelDisabled = interaction.DisabledOpacity, IconWrapper = $"{positioning.Absolute} start-0 {display.Flex} {flexbox.Align.Center} {flexbox.Justify.Center} {sizing.Icon.Md} opacity-0 peer-checked:opacity-100 {interaction.PointerEventsNone}" }, new TwRatingTheme { Colors = new() { Primary = "text-purple-600 dark:text-purple-400", Accent = "text-fuchsia-600 dark:text-fuchsia-400", Success = "text-green-600 dark:text-green-400", Danger = "text-red-600 dark:text-red-400", Warning = "text-amber-600 dark:text-amber-400", Info = "text-blue-600 dark:text-blue-400", Light = "text-gray-100 dark:text-white", Dark = "text-gray-950 dark:text-gray-950", }, Base = $"{display.InlineFlex} {flexbox.Align.Center} gap-0.5 {rounded.Sm} select-none touch-manipulation", EmptyFocusRing = "has-[input[data-rating-empty]:focus-visible]:ring-2 has-[input[data-rating-empty]:focus-visible]:ring-purple-500 dark:has-[input[data-rating-empty]:focus-visible]:ring-purple-400", Item = $"{positioning.Relative} {display.InlineFlex} {flexbox.ShrinkNone} {rounded.Sm} leading-none", ItemFocusRing = "has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-purple-500 dark:has-[input:focus-visible]:ring-purple-400", ItemHover = $"{transition.TransformFast} {transition.EaseInOut} hover:scale-115 motion-reduce:hover:scale-100", Visual = $"{positioning.Relative} {display.InlineFlex} {interaction.PointerEventsNone}", Empty = "text-[oklch(21%_0.006_285.885)]/30 dark:text-[oklch(97.807%_0.029_256.847)]/30 forced-colors:text-[GrayText]", Clip = $"{positioning.Absolute} inset-y-0 start-0 {display.Flex} {overflow.Hidden} whitespace-nowrap", Filled = $"{flexbox.ShrinkNone} forced-colors:text-[Highlight]", Pop = "tw-rating-pop", Input = "sr-only", HalfTarget = $"{positioning.Absolute} inset-y-0 start-0 z-10 w-1/2 {interaction.PointerCursor}", FullTarget = $"{positioning.Absolute} inset-0 {interaction.PointerCursor}", Disabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", Small = "text-lg", Medium = "text-2xl", Large = "text-4xl" }, new TwSliderTheme { Colors = new() { Primary = $"{background.Medium.Primary} {darkBackground.Medium.Primary}", Accent = $"{background.Medium.Accent} {darkBackground.Medium.Accent}", Success = $"{background.Medium.Success} {darkBackground.Medium.Success}", Danger = $"{background.Medium.Danger} {darkBackground.Medium.Danger}", Warning = $"{background.Medium.Warning} {darkBackground.Medium.Warning}", Info = $"{background.Medium.Info} {darkBackground.Medium.Info}", Light = $"{background.Medium.Light} {darkBackground.Medium.Light}", Dark = $"{background.Dark.Dark} {darkBackground.Dark.Dark}", }, Wrapper = $"{positioning.Relative} {display.Flex} {flexbox.Align.Center} {sizing.FullWidth} h-6 select-none", Base = $"peer {positioning.Absolute} inset-0 z-20 {sizing.Full} m-0 {transparentBackground} appearance-none {interaction.PointerCursor} {interaction.FocusOutlineNone} focus-visible:outline-hidden touch-manipulation", Track = $"{positioning.Absolute} inset-x-0 top-1/2 {overflow.Hidden} h-2 {neutralTrackStrong} {borderWidth.Thin} {neutralSurface.BorderStrong} {rounded.Full} -translate-y-1/2 {interaction.PointerEventsNone}", Fill = $"{sizing.FullHeight} forced-colors:bg-[Highlight]", Thumb = $"{positioning.Absolute} top-1/2 z-10 {sizing.Icon.Md} bg-white dark:bg-gray-100 {rounded.Full} {borderWidth.Thick} -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 {shadows.Md} ring-1 ring-black/5 peer-hover:scale-110 peer-active:scale-95 {transition.TransformFast} {transition.EaseInOut} {interaction.PointerEventsNone}", Bubble = $"{positioning.Absolute} bottom-full z-10 mb-2 px-2 py-1 whitespace-nowrap {typography.Size.Xs} {typography.Weight.Medium} tabular-nums {overlayTheme.Popover.Background} {neutralText.Heading} {overlayTheme.Popover.Border} {rounded.Md} -translate-x-1/2 rtl:translate-x-1/2 {shadows.Lg} opacity-0 scale-95 peer-hover:opacity-100 peer-hover:scale-100 peer-focus-visible:opacity-100 peer-focus-visible:scale-100 transition-[opacity,transform] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut} {interaction.PointerEventsNone}" }, new TwStepperTheme { HorizontalList = $"hidden sm:flex sm:items-start {sizing.FullWidth}", VerticalList = $"{display.Flex} {flexbox.Col} {sizing.FullWidth}", Step = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center} {spacing.Gap.Sm} shrink-0 {typography.AlignCenter}", VerticalStep = $"group {display.Flex} {spacing.Gap.Lg}", VerticalIndicatorColumn = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center}", VerticalContentColumn = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm} {flexbox.Flex1} {sizing.MinWidthNone} pt-2.5 pb-8 group-last:pb-0", Connector = $"{flexbox.Flex1} h-0.5 mt-[19px] mx-1 border-t-2 {rounded.Full} {transition.ColorsSlow}", VerticalConnector = $"{flexbox.Flex1} w-0 min-h-6 my-1 border-s-2 {rounded.Full} {transition.ColorsSlow}", ConnectorNeutral = neutralSurface.Border, Circle = $"{display.Flex} {anchor.Center} shrink-0 {sizing.Icon.Xl} {rounded.Full} {typography.Weight.Semibold} {typography.Size.Sm} {transition.ColorsFast} {interaction.FocusOutlineNone}", CircleUpcoming = $"{neutralSurface.Background} {neutralText.Muted} border-2 {neutralSurface.BorderStrong}", CircleDisabled = $"{interaction.DisabledOpacity} {interaction.DisabledCursor}", CircleClickable = interaction.PointerCursor, CircleFrame = $"{display.InlineFlex} shrink-0 p-0.5 border-2 {rounded.Full} {transition.ColorsFast}", CircleFrameInactive = "border-transparent", CircleUpcomingClickable = $"{neutralRowHover} hover:border-[oklch(21%_0.006_285.885)]/45 dark:hover:border-[oklch(97.807%_0.029_256.847)]/45 {neutralHoverText}", LabelActive = typography.Weight.Semibold, CircleIcon = "leading-none", Label = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Heading}", LabelUpcoming = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Muted}", Description = $"{typography.Size.Xs} {neutralText.Subtle}", Content = $"{spacing.MarginTop.Xl} {spacing.Padding.Xl} {borderWidth.Thin} {neutralSurface.Border} {rounded.Md}", VerticalContent = "pt-2", MobileContainer = $"{display.Flex} sm:hidden {flexbox.Col} {spacing.Gap.Sm} {sizing.FullWidth}", MobileLabel = $"{typography.Size.Sm} {typography.Weight.Medium} {neutralText.Heading}", MobileProgressLabel = display.ScreenReaderOnly }, new TwSwitchTheme { Colors = new() { Primary = "peer-checked:bg-purple-600 dark:peer-checked:bg-purple-500", Accent = "peer-checked:bg-fuchsia-600 dark:peer-checked:bg-fuchsia-500", Success = "peer-checked:bg-green-600 dark:peer-checked:bg-green-500", Danger = "peer-checked:bg-red-600 dark:peer-checked:bg-red-500", Warning = "peer-checked:bg-yellow-600 dark:peer-checked:bg-yellow-500", Info = "peer-checked:bg-blue-600 dark:peer-checked:bg-blue-500", Light = "peer-checked:bg-white dark:peer-checked:bg-gray-300", Dark = "peer-checked:bg-gray-900 dark:peer-checked:bg-gray-800", }, Switch = $"{positioning.Absolute} top-1/2 start-0.5 {sizing.Icon.Md} bg-white {rounded.Full} -translate-y-1/2 {shadows.Md} ring-1 ring-black/15 forced-colors:bg-[ButtonText] peer-checked:translate-x-full rtl:peer-checked:-translate-x-full {transition.TransformFast} {transition.EaseInOut}", Track = $"{positioning.Absolute} inset-0 bg-[oklch(88%_0_0)] dark:bg-[oklch(34%_0.018_253)] {rounded.Full} {neutralHairlineRing} {borderWidth.Thin} {neutralSurface.BorderStrong} forced-colors:peer-checked:bg-[Highlight] peer-disabled:opacity-40 transition-[background-color,opacity] {transition.DurationFast} motion-reduce:transition-none {transition.EaseInOut} peer-disabled:pointer-events-none", WrapperSize = "w-10 h-6", Base = "peer sr-only", LabelBase = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md} {inputLabelText} select-none", LabelInteractiveCursor = interaction.PointerCursor, LabelNonInteractiveCursor = interaction.PointerEventsNone, LabelDisabled = interaction.DisabledOpacity }, new TwSpinnerTheme { Colors = new() { Primary = "border-t-purple-600 dark:border-t-purple-500", Accent = "border-t-fuchsia-600 dark:border-t-fuchsia-500", Success = "border-t-green-600 dark:border-t-green-500", Danger = "border-t-red-600 dark:border-t-red-500", Warning = "border-t-yellow-500 dark:border-t-yellow-500", Info = "border-t-blue-600 dark:border-t-blue-500", Light = "border-t-white", Dark = "border-t-gray-900", }, Wrapper = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Md}", Base = $"{display.InlineBlock} {rounded.Full} animate-spin motion-reduce:[animation-duration:3s]", Track = neutralSurface.Border, LightTrack = "border-white/25", DarkTrack = "border-gray-900/15", Small = $"{sizing.Icon.Md} border-3", Medium = $"{sizing.Icon.Xl} border-5", Large = "size-12 border-5", Label = $"{typography.Size.Sm} {neutralText.Muted}" }, new TwTimePickerTheme { PickerRoot = positioning.Relative, IconWrapper = $"{positioning.Absolute} {inset.Top} {inset.Start} {display.Flex} {anchor.Center} w-10 ps-2 {interaction.PointerCursor}", IconGlyph = $"{sizing.Icon.Md} {neutralText.Subtle}", TextfieldPadding = "ps-10 pe-3", NativeInputAppearance = "appearance-none !flex items-center [&::-webkit-date-and-time-value]:min-h-0 [&::-webkit-date-and-time-value]:text-start [&::-webkit-datetime-edit]:p-0", PanelWrapper = $"{positioning.Absolute} top-full start-0 z-120 {spacing.MarginTop.Md}", RangeStageTabsContainer = $"{display.Flex} {spacing.Gap.Sm} {spacing.Padding.Sm} {rounded.Lg} {neutralTrack} {spacing.MarginBottom.Md}", RangeStageTabInactive = neutralText.Subtle, StageTabBase = $"{flexbox.Flex1} py-1.5 {typography.Size.Sm} {typography.Weight.Medium} {typography.AlignCenter} {interaction.PointerCursor} {transition.ColorsFast} {focusRing} {interaction.FocusOutlineNone}", StageTabActive = $"bg-white dark:bg-[oklch(34%_0.018_253)] {neutralText.Heading} {shadows.Sm}", StageTabHover = neutralHoverText, BodySurface = $"{spacing.Padding.Xl} {typography.AlignCenter} {typography.Weight.Medium} {neutralText.Heading}", BodyRoot = "", BodyInner = $"{spacing.Padding.Md} {typography.AlignCenter} {typography.Weight.Medium} {neutralText.Heading}", ContentRow = $"{display.Flex} {anchor.Center} {spacing.Gap.Lg}", Column = $"{display.Flex} {flexbox.Col} {flexbox.Align.Center} {spacing.Gap.Sm}", StepButton = $"{neutralText.Subtle} hover:text-purple-600 dark:hover:text-purple-400 {interaction.PointerCursor}", NumberWrapper = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Center}", NumberInput = $"w-12 py-1 {typography.AlignCenter} {typography.Size.Lg} {typography.Weight.Semibold} {neutralText.Heading} {transition.ColorsFast} {rounded.Md} {focusRing} {interaction.FocusOutlineNone}", Separator = $"self-center px-1 {typography.Size.Lg} {typography.Weight.Semibold} {neutralText.Subtle}", AmPmWrapper = $"{display.Flex} {flexbox.Align.Center} ms-2", AmPmButtonClass = "min-w-12" }, new TwTableTheme { Wrapper = $"{positioning.Relative} overflow-auto focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-purple-600 dark:focus-visible:outline-purple-300", ContainerClip = overflow.Hidden, Base = $"{sizing.FullWidth} {typography.Size.Sm} text-start {neutralText.Heading}", FixedLayout = "table-fixed", Bordered = $"{borderWidth.Thin} {neutralSurface.Border}", Header = $"{typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Secondary} {neutralSurface.BackgroundSubtle} border-b {neutralSurface.Border}", StickyHeader = $"{positioning.Sticky} top-0 z-10", Body = neutralSurface.Background, BodyStriped = "[&>tr:nth-child(even)]:bg-[oklch(98%_0_0)] [&>tr:nth-child(even)]:dark:bg-[oklch(23.26%_0.014_253.1)]", BodyHoverable = "[&>tr:hover]:!bg-[oklch(95%_0_0)] [&>tr:hover]:dark:!bg-[oklch(21.15%_0.012_254.09)] [&>tr]:transition-colors [&>tr]:duration-200 [&>tr]:motion-reduce:transition-none", RowDivider = "divide-y divide-[oklch(94%_0_0)] dark:divide-[oklch(21.15%_0.012_254.09)]", Footer = $"border-t {neutralSurface.Border}", SearchColumn = "md:w-1/2", SortIcon = $"{typography.Size.Sm} {neutralText.Subtle} {neutralHoverText}", HeaderCellPadding = "px-4 py-2.5", BodyCellPadding = $"px-4 py-2.5 {typography.WrapBreakWord}", EmptyState = $"py-8 {typography.AlignCenter} {neutralText.Muted}", ResizeHandle = $"{positioning.Absolute} z-20 flex w-3 -translate-x-1/2 justify-center cursor-col-resize touch-none select-none before:block before:h-full before:w-px before:bg-gray-300 dark:before:bg-gray-600 hover:before:w-0.5 hover:before:bg-purple-500 active:before:bg-purple-600 dark:hover:before:bg-purple-400 focus-visible:outline-none focus-visible:before:w-0.5 focus-visible:before:bg-purple-600 dark:focus-visible:before:bg-purple-300", GroupByColumn = "w-full sm:w-56", GroupRow = $"{neutralSurface.BackgroundSubtle} {neutralText.Heading}", GroupToggle = $"{display.InlineFlex} {flexbox.Align.Center} {spacing.Gap.Sm} {rounded.Md} -mx-1 px-1 {typography.Weight.Semibold} {interaction.PointerCursor} focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-purple-600 dark:focus-visible:outline-purple-300", GroupCount = $"{typography.Weight.Medium} {neutralText.Muted}", LoadingCell = $"py-2.5 {typography.AlignCenter} {neutralText.Muted}", ActionsCell = "w-px whitespace-nowrap", EditingRow = "!bg-purple-50 dark:!bg-purple-500/10", FilterPanel = $"z-50 w-72 max-w-[calc(100vw-1rem)] {rounded.Lg} {borderWidth.Thin} {neutralSurface.Border} {neutralSurface.Background} shadow-lg {spacing.Padding.Md} {interaction.FocusOutlineNone}", FilterHeading = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm} {spacing.MarginBottom.Md} {typography.Size.Sm} {typography.Weight.Semibold} {neutralText.Heading}" }, new TwToastTheme { Colors = new() { Primary = $"{background.Light.Primary} {darkBackground.Light.Primary} {text.Dark.Primary} {borderWidth.AccentEdge} {borderColors.Primary}", Accent = $"{background.Light.Accent} {darkBackground.Light.Accent} {text.Dark.Accent} {borderWidth.AccentEdge} {borderColors.Accent}", Success = $"{background.Light.Success} {darkBackground.Light.Success} {text.Dark.Success} {borderWidth.AccentEdge} {borderColors.Success}", Danger = $"{background.Light.Danger} {darkBackground.Light.Danger} {text.Dark.Danger} {borderWidth.AccentEdge} {borderColors.Danger}", Warning = $"{background.Light.Warning} {darkBackground.Light.Warning} {text.Dark.Warning} {borderWidth.AccentEdge} {borderColors.Warning}", Info = $"{background.Light.Info} {darkBackground.Light.Info} {text.Dark.Info} {borderWidth.AccentEdge} {borderColors.Info}", Light = $"{background.Light.Light} {darkBackground.Light.Light} {text.Dark.Dark} {borderWidth.AccentEdge} {borderColors.Light}", Dark = $"{background.Dark.Dark} {text.Light.Light} {borderWidth.AccentEdge} {borderColors.Dark}" }, HeaderClasses = $"{display.Flex} {flexbox.Col} {flexbox.Flex1} {spacing.Gap.Md} {sizing.MinWidthNone}", IconContainer = flexbox.ShrinkNone, Title = $"{typography.Weight.Semibold} {typography.Size.Sm} {typography.WrapBreakWord}", Message = $"{typography.Size.Sm} {typography.WrapBreakWord}", Container = $"{positioning.Fixed} bottom-0 end-4 z-140 {display.Flex} {flexbox.Col} {spacing.Gap.Md} max-w-md {spacing.Padding.Xl}", Toast = $"{display.Flex} {flexbox.Align.Start} {spacing.Gap.Md} {spacing.Padding.Xl} {shadows.Lg} {transition.ColorsFast} {transition.EaseInOut}", ToastWidth = "w-[300px] max-w-full", Timestamp = $"{typography.Size.Xs} opacity-70", CloseButton = $"{flexbox.ShrinkNone} {spacing.Padding.Sm} {neutralHoverFill} {rounded.Full} focus-visible:ring-2 focus-visible:ring-current {transition.ColorsFast} {interaction.FocusOutlineNone}" }, new TwCalendarTheme { Container = $"{display.Flex} {flexbox.Col} {sizing.FullWidth} {spacing.Gap.Lg}", Header = $"{display.Flex} {flexbox.Align.Center} {flexbox.Justify.Between} {flexbox.Wrap} {spacing.Gap.Lg} pb-4 border-b {neutralSurface.Border}", HeaderDateGroup = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm}", HeaderTitleRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Md}", HeaderTitle = $"{typography.Size.Lg} {typography.Weight.Semibold} {neutralText.Heading}", HeaderSubtitle = $"{typography.Size.Xs} {neutralText.Muted}", NavButton = $"{display.Flex} {anchor.Center} size-8 {rounded.Full} {neutralSurface.Hover} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast}", ViewButtonActive = $"{background.Lightest.Primary} {darkBackground.Dark.Primary}", AddButton = "shrink-0", SearchButton = neutralText.Subtle, ScrollContainer = "overflow-y-auto", TimeGutter = $"{positioning.Relative} {display.Flex} {flexbox.Col} {flexbox.ShrinkNone} w-10 sm:w-16 text-end {spacing.Padding.Sm}", TimeGutterLabel = $"text-[10px] sm:text-xs {neutralText.Subtle} -translate-y-2", NowIndicatorLabel = $"{positioning.Absolute} end-1 sm:end-2 -translate-y-1/2 text-[10px] sm:text-xs {typography.Weight.Semibold} {text.Medium.Primary} {darkText.Light.Primary} {neutralSurface.Background} px-1 {rounded.Sm} {interaction.PointerEventsNone}", NowIndicatorLine = $"{positioning.Absolute} inset-x-0 border-t-2 {borderColors.Primary} {interaction.PointerEventsNone} z-10", NowIndicatorDot = $"{positioning.Absolute} -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 size-2.5 {rounded.Full} {background.Medium.Primary} {interaction.PointerEventsNone} z-10", SlotRow = $"h-12 border-t {neutralSurface.BorderSubtle}", SlotRowHover = $"{neutralSurface.Hover} {interaction.PointerCursor}", DayColumnHeader = $"{sizing.MinWidthNone} {typography.Size.Xs} {typography.Weight.Semibold} {typography.AlignCenter} {neutralText.Secondary} py-2 border-b {neutralSurface.Border} {focusRingInset} {interaction.FocusOutlineNone}", DayColumnHeaderLabel = "sr-only sm:not-sr-only", DayColumnHeaderCompact = "gap-0.5 sm:hidden", DayColumnHeaderWeekday = $"text-[10px] {typography.Weight.Medium} {textTransform.Uppercase} {neutralText.Subtle}", DayColumnHeaderDayNumber = $"{display.Flex} {anchor.Center} size-7 {rounded.Full} {typography.Size.Sm} {neutralText.Heading}", DayColumnHeaderDayNumberToday = $"{background.Medium.Primary} {text.Medium.Light}", DayColumnDivider = $"border-s {neutralSurface.BorderSubtle}", EventChip = $"{positioning.Absolute} {overflow.Hidden} {rounded.Sm} {display.Flex} {flexbox.Col} {flexbox.Align.Start} text-start {borderWidth.AccentEdge} {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} {spacing.Padding.Sm} {interaction.PointerCursor} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast}", EventChipTitle = $"{typography.Size.Xs} {typography.Weight.Semibold} {typography.WrapBreakWord}", EventChipTime = $"{typography.Size.Xs} opacity-75", EventChipCompact = "max-sm:border-s-2 max-sm:px-0.5", EventChipTitleCompact = "max-sm:text-[10px] max-sm:leading-tight", EventChipTimeCompact = "max-sm:hidden", EventChipReadOnly = $"{interaction.ReadonlyCursor} opacity-90", EventChipDraggable = "cursor-grab active:cursor-grabbing", DropPlaceholder = $"{overflow.Hidden} {rounded.Sm} border-2 border-dashed {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} {typography.Size.Xs} opacity-70 z-10", TodayHighlight = $"animate-pulse motion-reduce:animate-none [animation-iteration-count:1] {background.Light.Primary} dark:bg-purple-500/50", AllDayRow = $"border-b {neutralSurface.Border}", AllDayLabel = $"{flexbox.ShrinkNone} w-10 sm:w-16 {spacing.Padding.Sm} text-end text-[10px] sm:text-xs {neutralText.Subtle}", AllDayGrid = "gap-y-1 py-1", AllDayChipInset = "mx-0.5", SegmentSpan = $"{positioning.Relative} z-10", SegmentContinuesBefore = "rounded-s-none", SegmentContinuesAfter = "rounded-e-none", SegmentSpacer = $"h-5 {flexbox.ShrinkNone}", MonthGrid = $"{sizing.FullWidth} border-collapse table-fixed", MonthCell = $"align-top {spacing.Padding.Sm} max-sm:p-0.5 border {neutralSurface.BorderSubtle} h-24", MonthCellPrevNext = $"{neutralSurface.BackgroundSubtle} {neutralText.Subtle}", MonthDayNumber = $"{display.Block} {sizing.FullWidth} text-start {typography.Size.Xs} {typography.Weight.Medium} {neutralText.Heading}", MonthEventList = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm} mt-1", MonthEventRow = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Sm} {sizing.FullWidth} {overflow.Hidden} {rounded.Sm} text-start max-sm:border-s-2 max-sm:px-0.5 {borderWidth.AccentEdge} {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {text.Dark.Primary} {darkText.Light.Primary} px-1.5 py-0.5 {interaction.PointerCursor} {focusRing} {interaction.FocusOutlineNone} {transition.ColorsFast}", MonthEventName = $"{typography.Size.Xs} max-sm:text-[10px] {typography.Weight.Semibold} truncate max-sm:text-clip", MonthEventTime = $"{typography.Size.Xs} opacity-75 {flexbox.ShrinkNone} max-sm:hidden", MonthOverflowLabel = $"{typography.Size.Xs} max-sm:text-[10px] text-start whitespace-nowrap {neutralText.Subtle} {interaction.PointerCursor}", EventDialogFields = $"{display.Flex} {flexbox.Col} {spacing.Gap.Xl} -mt-3", EventDialogActions = $"{display.Flex} {flexbox.Justify.End} {spacing.Gap.Md} {spacing.MarginTop.Xl}", EventDialogAccent = $"h-1 {sizing.FullWidth} {rounded.Full} {background.Medium.Primary}", EventDialogDateRow = $"{display.Grid} grid-cols-1 sm:grid-cols-2 {spacing.Gap.Xl}", EventDialogSummary = $"{display.Flex} {flexbox.Align.Center} {spacing.Gap.Lg} {rounded.Md} {borderWidth.AccentEdge} {borderColors.Primary} {background.Lightest.Primary} {darkBackground.Dark.Primary} {neutralText.Heading} {spacing.Padding.Lg} {typography.Size.Sm}", EventDialogSummaryIcon = $"{flexbox.ShrinkNone} {text.Medium.Primary} {darkText.Light.Primary}", EventDialogReadOnlyField = $"{display.Flex} {flexbox.Col} {spacing.Gap.Sm}", EventDialogReadOnlyLabel = $"{typography.Size.Xs} font-normal tracking-wide {neutralText.Muted}", EventDialogReadOnlyValue = $"{typography.Size.Base} {neutralText.Heading} whitespace-pre-line" } ] }; } ``` This is the default theme. To use your own brand colors or only the components you use, [build your own Theme.cs](https://twblazor.com/theme) instead, and register it with `Theme.CreateTheme` in step 7. ### 7. Register TwBlazor services Register TwBlazor's services in **both** Program.cs files, pointing at the `Theme` class you just created in `{YourProjectName}.Client`. `{YourProjectName}.Client/Program.cs`: ```csharp using TwBlazor; var builder = WebAssemblyHostBuilder.CreateDefault(args); // ... existing template code ... builder.Services.AddTwBlazor(_ => { }, Theme.CreateDefaultTheme); await builder.Build().RunAsync(); ``` `{YourProjectName}/Program.cs` - since `Theme` lives in the other project, add a `using` for it: ```csharp using {YourProjectName}.Client; using TwBlazor; var builder = WebApplication.CreateBuilder(args); // ... existing template code ... builder.Services.AddTwBlazor(_ => { }, Theme.CreateDefaultTheme); ``` ### 8. Build your Tailwind CSS Install the [Tailwind CLI](https://tailwindcss.com/docs/installation/tailwind-cli) from the solution root - the outer `{YourProjectName}` folder that contains both `{YourProjectName}/` and `{YourProjectName}.Client/`: ```bash npm init -y npm install tailwindcss @tailwindcss/cli ``` Create an input stylesheet at `{YourProjectName}/wwwroot/css/input.css`. It lives in the host project, since that's what App.razor's `` tag references, but its `@source` directives need to reach into `{YourProjectName}.Client` too, because that's where MainLayout.razor and Theme.cs live. The keyframes at the bottom power `TwSkeleton`'s `Wave` variant - a shimmer effect Tailwind has no utility for, so it has to be real CSS rather than a class Tailwind can generate. Skip it if you don't use that variant: ```css @import "tailwindcss"; @source "../../**/*.razor"; @source "../../../{YourProjectName}.Client/**/*.razor"; @source "../../../{YourProjectName}.Client/Theme.cs"; /* Powers TwSkeleton's wave animation and TwProgress's Animated shimmer. */ @keyframes tw-wave { 0% { transform: translateX(-100%); } 50%, 100% { transform: translateX(100%); } } .tw-wave::after { content: ""; position: absolute; inset: 0; transform: translateX(-100%); background: linear-gradient(90deg, transparent, var(--tw-wave-color, rgb(255 255 255 / 40%)), transparent); animation: tw-wave 1.6s linear infinite; } .dark .tw-wave::after { background: linear-gradient(90deg, transparent, var(--tw-wave-color, rgb(255 255 255 / 8%)), transparent); } /* Powers TwIcons's pulse animation */ .tw-icon-pulse::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background-color: currentColor; opacity: 0; transform: scale(0); transition: transform 500ms ease-out, opacity 450ms ease-out; pointer-events: none; } .tw-icon-pulse:active::after { opacity: 0.25; transform: scale(1); transition: transform 120ms ease-out, opacity 80ms ease-out; } /* Powers TwRating's "pop" when a rating is picked: a quick overshoot that settles back. Each pick flips the element's data-pop between 0 and 1, and with it the keyframe name, because re-applying the same animation to an element does not replay it. */ @keyframes tw-rating-pop { 0% { transform: scale(1); } 35% { transform: scale(1.35); } 65% { transform: scale(0.92); } 100% { transform: scale(1); } } @keyframes tw-rating-pop-alt { 0% { transform: scale(1); } 35% { transform: scale(1.35); } 65% { transform: scale(0.92); } 100% { transform: scale(1); } } .tw-rating-pop { animation: tw-rating-pop 420ms ease-out both; } .tw-rating-pop[data-pop="1"] { animation-name: tw-rating-pop-alt; } @media (prefers-reduced-motion: reduce) { .tw-wave::after { animation: none; } .tw-icon-pulse::after { transition: none; } .tw-rating-pop { animation: none; } } ``` Then build it to `{YourProjectName}/wwwroot/css/output.css`, the file already referenced by the `` tag you added to App.razor in step 3: ```bash npx @tailwindcss/cli -i ./{YourProjectName}/wwwroot/css/input.css -o ./{YourProjectName}/wwwroot/css/output.css --watch ``` ### 9. Try it out Add a test page to confirm everything is wired up. Since it needs to be interactive under WebAssembly, it has to live in the Client project. Create `{YourProjectName}.Client/Pages/ComponentTest.razor`: ```razor @page "/component-test" @rendermode InteractiveWebAssembly Component Test

Component Test

Everything below is wired up and interactive - you're good to go!
``` ```csharp private int count; private bool switchOne; private bool switchTwo = true; private bool switchThree; private void Increment() => count++; ``` Run the app and go to `/component-test`. You should see a green success alert, a button whose label counts up each click, and three interactive switches. --- # TwIcon > TwIcon is a Blazor icon component for Bootstrap Icons. Pass an Icon enum value, style it with Tailwind classes, or add OnClick to make an icon button. Documentation page: https://twblazor.com/icon ## Icons Use TwIcon to display any Bootstrap icon. ```razor
``` ## Icon buttons Passing `OnClick` wraps the icon in a circular button. It gets a hover state-layer and a press "pulse" automatically, even without a `Color` set. ```razor
``` ## Icon button tooltips Set `Tooltip` on an icon button to explain what it does on hover and keyboard focus. The tooltip is a `role="tooltip"` element linked via `aria-describedby`, and can be dismissed with `Escape`. Keep providing an `AriaLabel`, since the tooltip only supplements the button's accessible name. It has no effect on a non-interactive icon (no `OnClick`), which can't receive focus. ```razor
``` ## Icon size You can control icon sizes using [Tailwind CSS font size](https://tailwindcss.com/docs/font-size) classes or passing in your owm. ```razor
``` ## Icon library Browse through all available Bootstrap icons. Click on any icon to copy its enum value. Copied enum value Load more No icons found matching "" ## Keyboard navigation An icon is decorative and is not a Tab stop. An icon with OnClick is a button. | Key | What it does | | --- | --- | | `Tab` | Moves focus to a clickable icon. | | `Enter` or `Space` | Activates a clickable icon. | | `Escape` | Hides the icon's tooltip, if it has one. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwIcon Represents an icon component that displays Bootstrap icons. | Parameter | Type | Description | | --- | --- | --- | | `OnClick` | `EventCallback` | Gets or sets the callback that is invoked when the icon is clicked. | | `Disabled` | `bool` | Gets or sets whether the button state for the icon button is disabled if an onclick parameter is passed. | | `Readonly` | `bool` | Gets or sets whether the icon button is unavailable but still focusable. It is announced as unavailable (`aria-disabled`) and ignores clicks, without dropping out of the tab order. | | `Tooltip` | `string?` | Gets or sets the text of a tooltip shown when the icon button is hovered or keyboard-focused. | | `OnMouseOver` | `EventCallback` | Gets or sets the callback that is invoked when the mouse hovers over the icon. | | `Icon` | `Icon` | Gets or sets the icon to display. | | `ButtonVariant` | `ButtonVariant` | Gets or sets the button variant to display. | | `Plain` | `bool` | Gets or sets whether the wrapped icon button skips its default button chrome (sizing, variant/color classes, focus ring, shadow), leaving only `Class` applied. | | `Color` | `Color?` | Gets or sets the color of the icon. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | --- # Localization > Translate twblazor components and set date and time formats: built in languages, your own .resx files, and options.Localization in AddTwBlazor. Documentation page: https://twblazor.com/localization ## Overview Every piece of text a twblazor component renders by itself, such as button labels, placeholders, validation messages and the names screen readers announce, comes from a resource file. English is built in and 23 more languages ship with the package, so a component follows the language of your application with nothing to set up. Dates and times are localized the same way. Month and day names, the first day of the week, 12 or 24 hour time and the order of day, month and year all follow the culture, and each one can be set in `AddTwBlazor`. Text you pass to a component yourself, such as a `Label` or a column title, is rendered as it is. Translating it stays in your application, with whatever you already use for that. ## Supported languages The language is chosen from `CultureInfo.CurrentUICulture`. A regional culture uses its language file, so `es-MX` and `es-AR` both use Spanish, `ar-EG` uses Arabic, and `zh-HK` uses Traditional Chinese. Wu Chinese is written in Simplified Chinese, so it is covered by `zh-Hans`. A language that is not in this table falls back to English. **Translations other than English were produced by AI** and have not been reviewed by native speakers, so some wording may be inaccurate or unnatural. If you spot something that could read better, please [contribute a correction](https://twblazor.com/localization#localization-contributing). ## Choose the language twblazor does not pick a language itself. It reads the culture your application is running under, which is what Blazor's own localization sets, so if your application already switches culture the components switch with it. In Blazor WebAssembly set the culture before the application runs. In a server application use request localization, so each user gets the culture of their request. ```csharp // Blazor WebAssembly: Program.cs var culture = new CultureInfo("es"); CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture; // Blazor Server: Program.cs app.UseRequestLocalization(new RequestLocalizationOptions() .SetDefaultCulture("en-GB") .AddSupportedCultures("en-GB", "es", "ja") .AddSupportedUICultures("en-GB", "es", "ja")); ``` To pin every component to one culture whatever the application is running under, set `Culture` on the options. It applies to both the text and the formatting. ```csharp builder.Services.AddTwBlazor(options => { options.Localization.Culture = new CultureInfo("ja"); }, Theme.CreateTheme); ``` Blazor WebAssembly only downloads the language files for the culture the application starts with. Changing the language while it runs needs a page reload, and `BlazorWebAssemblyLoadAllGlobalizationData` has to be on for cultures outside the default set. This is how Blazor localization works in general and is not specific to twblazor. ## Right to left languages Arabic, Persian, Urdu and Western Punjabi are read right to left, and so is any other culture .NET reports as right to left, such as Hebrew. Components mirror their layout and swap the Left and Right arrow keys for those cultures. The page has to carry the matching `dir` attribute: wrap your layout in a [TwDirectionProvider](https://twblazor.com/direction-provider.md), or set `dir` on the `html` element yourself. ```razor @* MainLayout.razor *@ @Body ``` To set the direction whatever the culture, use `options.Localization.Direction`. ```csharp builder.Services.AddTwBlazor(options => { options.Localization.Direction = TextDirection.RightToLeft; }, Theme.CreateTheme); ``` ## Change or add text with your own resource files To reword a string, or to add a language twblazor does not ship, add `.resx` files to your own project: one neutral file, and one more for each language. The name of each entry is a key from `TwStrings`, such as `Pagination_NextPage`. ```text MyApp/ Resources/ TwBlazorStrings.resx the neutral file, used when no language file matches TwBlazorStrings.nl.resx Dutch TwBlazorStrings.sv.resx Swedish ``` Then register the file family. Only the keys you want to change need to be there. Anything missing falls back to twblazor's own file for that language, then to English. ```csharp using System.Resources; builder.Services.AddTwBlazor(options => { options.Localization.AddResource( new ResourceManager("MyApp.Resources.TwBlazorStrings", typeof(Program).Assembly)); }, Theme.CreateTheme); ``` A value with placeholders keeps them, so `Page {0} of {1}` becomes `Pagina {0} van {1}`. Text that counts something has a singular and a plural key, such as `Sidebar_ResultsOne` and `Sidebar_ResultsOther`. ```xml Sluiten Pagina {0} van {1} ``` Several file families can be registered. They are searched last added first. The full list of keys, with the English text of each, is the `TwStrings` class and [TwBlazorStrings.resx](https://github.com/twblazor/twblazor/blob/develop/src/TwBlazor/Resources/TwBlazorStrings.resx). ## Change text on one component A component parameter always wins over the resource files, so a single component can say something different from the rest of the application. ```razor ``` ## Date and time formats Calendars, pickers and charts take their formats from `options.Localization.Formats`. Every value is optional and is a .NET date and time format string. Anything you leave out comes from the culture, so most applications set nothing here. When the application has no culture of its own (the invariant culture), twblazor uses British formats: a 24 hour clock, day before month, and weeks that start on Monday. ```csharp builder.Services.AddTwBlazor(options => { options.Localization.Formats.FirstDayOfWeek = DayOfWeek.Sunday; options.Localization.Formats.Use12HourClock = true; options.Localization.Formats.LongDate = "dddd, d MMMM yyyy"; options.Localization.Formats.DateInput = "dd.MM.yyyy"; }, Theme.CreateTheme); ``` The picker input formats are the ones users type, so they stay fixed unless you change them: the date pickers use the theme's `dd/MM/yyyy` and the time pickers use a 24 hour clock, whatever the culture. To make the pickers type and parse the way a culture writes dates, copy its patterns in one call. ```csharp // For en-US this sets M/d/yyyy, h:mm tt and a 12 hour clock. options.Localization.Formats.UseCultureInputFormats(new CultureInfo("en-US")); ``` A format can also live in a resource file, so each language carries its own. Add an entry named `Format_ShortTime`, `Format_LongDate` and so on to the language's file. A value set on the options wins over the resource file, which wins over the culture. A component parameter such as `Format` or `Is12HourFormat` wins over all three. ## Use your own localizer Components read their text through the `ITwLocalizer` service. If your strings live somewhere other than `.resx` files, such as a database or an `IStringLocalizer`, register your own implementation and `AddTwBlazor` will leave it in place. ```csharp public class MyLocalizer(TwBlazorOptions options, IStringLocalizer strings) : TwLocalizer(options) { protected override string? GetString(string key, CultureInfo culture) { var text = strings[key]; return text.ResourceNotFound ? base.GetString(key, culture) : text.Value; } } builder.Services.AddScoped(); builder.Services.AddTwBlazor(_ => { }, Theme.CreateTheme); ``` The same service is available to your own components, with the same keys and formats. ```razor @inject ITwLocalizer Localizer @Localizer.Formats.Format(DateTime.Today, Localizer.Formats.LongDate) ``` ## Improve a translation Each language is one file in [src/TwBlazor/Resources](https://github.com/twblazor/twblazor/tree/develop/src/TwBlazor/Resources). To correct a translation, edit the `value` of the entry and open a pull request. To add a language, copy `TwBlazorStrings.resx` to `TwBlazorStrings..resx` and translate the values. Keep the entry names and the `{0}` placeholders unchanged. The test suite checks every language file for unknown keys and missing placeholders, so a mistake there is caught before it ships. --- # TwMenu > TwMenu is a Blazor menu button component that opens a keyboard friendly menu of actions, tick options and labelled groups. Documentation page: https://twblazor.com/menu ## Basic menu Put `TwMenuItem`s in a `TwMenu`. Choosing an item runs its `OnClick`, closes the menu and returns focus to the button. The button tells screen readers that it opens a menu and whether the menu is open. ```razor

@(lastAction is null ? "Nothing chosen yet." : $"You chose {lastAction}.")

``` ```csharp private string? lastAction; ``` ## Icon only button Set `IconOnly` to show just the `Icon`. Give it an `AriaLabel`, which names the button for screen readers and shows as its tooltip; without one it is called "Options". ```razor ``` ## Options that can be ticked A `TwMenuCheckboxItem` is an option that is on or off. Bind `@bind-Checked`. Choosing it flips the tick and leaves the menu open, so several options can be changed in a row; set `CloseOnClick` to close it instead. Screen readers announce each option as ticked or not. ```razor

Grid @(showGrid ? "on" : "off"), rulers @(showRulers ? "on" : "off"), snapping @(snapToGrid ? "on" : "off").

``` ```csharp private bool showGrid = true; private bool showRulers; private bool snapToGrid; ``` ## Groups and dividers Use `TwMenuGroup` to put items under a heading, which screen readers read as the group's name, and `TwMenuDivider` for a line between items. The arrow keys pass over both. A `Disabled` item is skipped and cannot be chosen. ```razor ``` ## Inside a scrolling container The menu is placed with fixed positioning, so it is not clipped by a container that scrolls, such as a table, and it flips above its button or towards the start when there is no room. Scrolling the page closes it on desktop. ```razor File Actions @foreach (var file in _files) { @file } ``` ## Keyboard navigation The button tells screen readers that it opens a menu and whether the menu is open. The menu follows the ARIA menu pattern: one item has focus at a time, and the arrow keys move between them. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the menu's button. | | `Enter` or `Space` or `Arrow Down` | On the button: opens the menu with focus on its first item. | | `Arrow Up` | On the button: opens the menu with focus on its last item. | | `Arrow Down` or `Arrow Up` | In the menu: moves to the next or previous item, wrapping round at either end. Disabled items are skipped. | | `Home` or `End` | In the menu: moves to the first or last item. | | `A to Z` | In the menu: moves to the next item that starts with the typed letter. | | `Enter` or `Space` | In the menu: chooses the focused item. An action closes the menu and returns focus to the button; a tick option flips and the menu stays open. | | `Escape` | Closes the menu and returns focus to the button. | | `Tab` | Closes the menu and moves focus on. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwMenu A button that opens a menu of actions and options, such as a column's options in a table or a row's actions. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the menu's items. | | `Label` | `string?` | Gets or sets the text of the button that opens the menu. Also names the menu for assistive technology. | | `Icon` | `Icon?` | Gets or sets an icon for the button: before the `Label`, or on its own with `IconOnly`. | | `IconOnly` | `bool` | Whether the button shows only its `Icon`. Give it an `AriaLabel`, which is also shown as a tooltip; without one it is named with the localized `Menu_Options` text ("Options"). | | `Variant` | `ButtonVariant?` | Gets or sets the look of the button. Defaults to the button theme's own default. | | `Dense` | `bool` | Whether the button uses its compact size. | | `ButtonClass` | `string?` | Gets or sets extra classes for the button. | | `Disabled` | `bool` | Whether the button is disabled, so the menu cannot open. | | `OpenChanged` | `EventCallback` | Raised when the menu opens or closes. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwMenuItem An action in a `TwMenu`. Choosing it runs `OnClick` and closes the menu. | Parameter | Type | Description | | --- | --- | --- | | `Label` | `string?` | Gets or sets the item's text. Use `ChildContent` instead for richer content. | | `ChildContent` | `RenderFragment?` | Gets or sets the item's content, in place of `Label`. Keep it to text: an item is a single control, so it cannot hold links or buttons of its own. | | `StartIcon` | `Icon?` | Gets or sets an icon shown before the item's text. | | `OnClick` | `EventCallback` | Raised when a person chooses the item, by clicking it or pressing Enter or Space on it. | | `Disabled` | `bool` | Whether the item is disabled. It is skipped by the arrow keys and cannot be chosen. | | `CloseOnClick` | `bool` | Whether choosing the item closes the menu and returns focus to its button. Defaults to `true`. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwMenuCheckboxItem An option in a `TwMenu` that is on or off, such as whether a column is shown. Choosing it flips `Checked`, and by default leaves the menu open so several options can be changed in a row. | Parameter | Type | Description | | --- | --- | --- | | `Label` | `string?` | Gets or sets the item's text. Use `ChildContent` instead for richer content. | | `ChildContent` | `RenderFragment?` | Gets or sets the item's content, in place of `Label`. Keep it to text. | | `Checked` | `bool` | Gets or sets whether the option is on. Bind it with `@bind-Checked`. | | `CheckedChanged` | `EventCallback` | Raised with the new value when a person chooses the item. | | `Disabled` | `bool` | Whether the item is disabled. It is skipped by the arrow keys and cannot be changed. | | `CloseOnClick` | `bool` | Whether choosing the item closes the menu. Defaults to `false`. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwMenuGroup A labelled group of items in a `TwMenu`, such as the columns that can be shown or hidden. Assistive technology reads the `Label` as the group's name. | Parameter | Type | Description | | --- | --- | --- | | `Label` | `string?` | Gets or sets the group's heading. | | `ChildContent` | `RenderFragment?` | Gets or sets the group's items. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwMenuDivider A line between groups of items in a `TwMenu`. Assistive technology reads it as a separator, and the arrow keys pass over it. | Parameter | Type | Description | | --- | --- | --- | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwMenuTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwMenuTheme` by hand. --- # TwNavbar > TwNavbar is a responsive Blazor navbar with BrandContent, NavigationContent and ActionsContent slots, data-driven NavigationItems and keyboard support. Documentation page: https://twblazor.com/navbar ## Structured navbar `TwNavbar` provides `BrandContent`, `NavigationContent`, and `ActionsContent` slots for hand-written markup. Responsive collapse is enabled by default: below the `lg` breakpoint the links and actions fold away behind a toggle at the end of the bar. Opening it drops a full-width menu under the bar, on the same surface, with each link as a row tall enough to tap and the actions set apart underneath, centered in a row. A menu taller than the screen scrolls on its own. Shrink the preview to see it. ```razor Acme Home Products Pricing ``` ## Data-driven links Pass `NavigationItems` instead of hand-written `NavigationContent` to render links (with optional icons) from a `List`, and mark one active with `IsActive`. Other slots such as `BrandContent` and `ActionsContent` still work alongside it. ```razor Acme ``` ```csharp private readonly List _navigationItems = [ new() { Label = "Home", Href = "/", Icon = Icon.House_Door_Fill, IsActive = true }, new() { Label = "Products", Href = "#", Icon = Icon.Box_Seam_Fill }, new() { Label = "Pricing", Href = "#", Icon = Icon.Tag_Fill } ]; ``` ## Disable responsive collapse Set `DisableResponsiveCollapse` to keep the navigation and actions slots always visible with no mobile toggle - useful when a parent layout, such as `TwSidebar`, already owns a mobile toggle. `TwSidebar` sets this on its embedded navbar for exactly that reason. ```razor Acme Home Products ``` ## Keyboard navigation The navbar is a navigation landmark holding ordinary links. On a narrow screen the links sit behind a menu button. | Key | What it does | | --- | --- | | `Tab` | Moves to the next link or button. | | `Enter` | Follows the focused link. | | `Enter` or `Space` | On the menu button: opens or closes the menu. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwNavbar | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the child content of the component. | | `BrandContent` | `RenderFragment?` | Gets or sets the content rendered before the navigation menu. | | `NavigationContent` | `RenderFragment?` | Gets or sets custom content rendered in place of data-driven navigation items. | | `ActionsContent` | `RenderFragment?` | Gets or sets content rendered after the navigation links. | | `NavigationItems` | `List` | Gets or sets the navigation items rendered when `NavigationContent` is not supplied. | | `DisableResponsiveCollapse` | `bool` | Gets or sets whether the navbar's responsive menu toggle and collapse behavior is disabled. | | `ToggleAriaLabel` | `string?` | Gets or sets the accessible label for the responsive menu toggle. Defaults to the localized `Navbar_OpenMenu` text ("Open navigation menu"). | | `Fixed` | `bool` | Gets or sets a value indicating whether the navbar should be fixed at the top. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwSidebarTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwSidebarTheme` by hand. --- # TwNumeric > TwNumeric is a Blazor number input component. Bind any numeric type, set Min, Max and Step, format by culture, and add a prefix, suffix or clear button. Documentation page: https://twblazor.com/numeric ## Basic usage Bind `Value` with `@bind-Value`. The field is a `TwTextfield` with the `spinbutton` role, so screen readers announce its value and limits. Use the − and + buttons, Arrow Up and Arrow Down, or the mouse wheel while it has focus, to step the value. ```razor

Quantity: @quantity

``` ```csharp private int quantity = 1; ``` ## Numeric types `T` can be any built-in integer type, `decimal`, `double` or `float`. Integer types only accept whole numbers, and the mobile keyboard matches: a number pad for integers, and one with a decimal separator otherwise. ```razor
``` ```csharp private int seats = 2; private decimal weight = 1.5m; private double ratio = 0.25; ``` ## Min, max and step `Min` and `Max` limit the value: a typed value outside them is moved to the nearest limit, stepping stops at them, and the − or + button is disabled once it is reached. `Step` sets how far one step goes, and Page Up and Page Down take ten steps at once. ```razor
``` ```csharp private int guests = 2; private int volume = 50; ``` ## Formatting and culture Set `Format` to any .NET numeric format string, such as `N2` for two decimal places with thousands separators. The text is tidied into that format when it is committed. Typed text is parsed in `Culture`, which defaults to the culture set through `options.Localization`. ```razor

Value: @budget.ToString(CultureInfo.InvariantCulture)

``` ```csharp private decimal budget = 1250m; private readonly CultureInfo _german = CultureInfo.GetCultureInfo("de-DE"); ``` ## Prefix and suffix Use `Prefix` and `Suffix` to show a currency symbol or a unit inside the field. They are not part of the value, and screen readers hear them with it through `aria-valuetext`, such as "£12.50" or "75 kg". ```razor
``` ```csharp private decimal price = 12.5m; private int bodyWeight = 75; ``` ## Nullable and clearable Use a nullable `T`, such as `int?`, to let the field be left empty: emptying it sets the value to `null`. `Clearable` shows the textfield's clear button, disabled while the field is empty so the buttons never shift under the pointer. Clearing a non-nullable value sets it to zero, kept within `Min` and `Max`. ```razor

Age: @(age?.ToString() ?? "null")

``` ```csharp private int? age; private decimal discount = 10m; ``` ## Spin buttons and mouse wheel Set `HideSpinButtons` to hide the − and + buttons; the keys and wheel still step the value. While the field has focus the mouse wheel steps it: scrolling up increases it, or decreases it with `InvertMouseWheel`. Set `DisableMouseWheel` to let the wheel scroll the page instead. ```razor
``` ```csharp private int spinValue = 3; ``` ## Update on input Typed text is committed when the field loses focus or Enter is pressed. Set `BindEvent="oninput"` to update the value on every keystroke instead. Text that is not a number is only flagged once the user leaves the field. ```razor

Total: @liveTotal

``` ```csharp private int liveTotal; ``` ## Allowed characters Keys that cannot be part of a number are ignored: by default the digits, the culture's separators and, while `Min` is below zero, the minus sign. Set `Pattern` to a regular expression each typed character must match. Pasted text is parsed instead, and flagged when it is not a number. ```razor ``` ```csharp private int pin; ``` ## Variants and dense `Variant` and `Dense` work exactly as they do on `TwTextfield`, so a numeric field lines up with the other inputs. ```razor
``` ```csharp private int variantValue = 7; ``` ## Disabled and readonly `Disabled` dims the field and its buttons. `ReadOnly` keeps the value readable and focusable, but it cannot be stepped or typed over. ```razor
``` ## Validation Validation works as it does on `TwTextfield`: pass a `Validator` that returns an error message, or `null` when the value is valid, or set `Invalid` and `ErrorMessage` yourself. Text that is not a number shows "Enter a valid number." The message is tied to the field with `aria-describedby`, so screen readers read it with the field. ```razor
``` ```csharp private int? evenNumber; private int tickets = 5; private static Task ValidateEven(int? value) => Task.FromResult(value is int number && number % 2 != 0 ? "Enter an even number." : null); ``` ## Keyboard navigation A numeric field is a text input with the spinbutton role, so screen readers announce its value and limits. Its clear, decrease and increase buttons are not Tab stops, because the keys below do the same job. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves focus into or out of the field. | | `Arrow Up` or `Arrow Down` | Increases or decreases the value by one step, stopping at Max or Min. | | `Pg.Up` or `Pg.Down` | Increases or decreases the value by ten steps. | | `Enter` | Commits the typed value, when the field binds on change. | | `Arrow Left` or `Arrow Right` or `Home` or `End` | Moves the caret through the text. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwNumeric Represents a field for entering a number, with decrease and increase buttons, keyboard and mouse wheel stepping, and optional limits, formatting, prefix and suffix. | Parameter | Type | Description | | --- | --- | --- | | `Value` | `T` | Gets or sets the current value. | | `ValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the value changes. | | `Min` | `T` | Gets or sets the lowest value allowed. Defaults to the smallest value `T` can hold. | | `Max` | `T` | Gets or sets the highest value allowed. Defaults to the largest value `T` can hold. | | `Step` | `T` | Gets or sets how much one step changes the value. Defaults to 1. | | `Format` | `string?` | Gets or sets the .NET numeric format string the value is shown in, such as `N2` for two decimal places with thousands separators, or `C` for currency. Defaults to the general format. | | `Culture` | `CultureInfo?` | Gets or sets the culture the value is parsed and formatted in. Defaults to the culture set through `options.Localization`, or the current culture. | | `Pattern` | `string?` | Gets or sets a regular expression that each typed character must match, such as `[0-9]`. Keys that do not match are ignored. | | `BindEvent` | `string` | Gets or sets the name of the DOM event that commits typed text. Defaults to `onchange`, which commits when the user leaves the field. Set it to `oninput` to update the value on every keystroke. | | `Placeholder` | `string` | Gets or sets the placeholder text shown while the field is empty. | | `Required` | `bool` | Gets or sets whether a value is required. The field is marked required for the browser's own validation and announced as required by assistive technology. | | `HideSpinButtons` | `bool` | Gets or sets whether the decrease and increase buttons are hidden. The keys and mouse wheel still step the value. | | `Clearable` | `bool` | Gets or sets whether the text field's clear button (see `Clearable`) is shown at the end of the field. It is disabled while the field is empty. | | `InvertMouseWheel` | `bool` | Gets or sets whether scrolling the mouse wheel up decreases the value instead of increasing it. | | `DisableMouseWheel` | `bool` | Gets or sets whether the mouse wheel is ignored, so scrolling over the focused field scrolls the page instead of stepping the value. | | `Prefix` | `string?` | Gets or sets text shown at the start of the field, such as a currency symbol. | | `Suffix` | `string?` | Gets or sets text shown at the end of the field, such as a unit. | | `Validator` | `Func>?` | Gets or sets an optional asynchronous validator invoked with the new value whenever it changes. | | `OnFocus` | `EventCallback` | Gets or sets the callback that is invoked when the field is focused. | | `OnBlur` | `EventCallback` | Gets or sets the callback that is invoked when the field loses focus. | | `OnClick` | `EventCallback` | Gets or sets the callback invoked when the field is clicked. | | `OnKeyDown` | `EventCallback` | Gets or sets the callback invoked when a key is pressed while the field has focus. It runs before the key steps the value. | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwNumericTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwNumericTheme` by hand. --- # TwOnThisPage > TwOnThisPage is a Blazor table of contents component: an On this page list of section links that highlights the section being read as you scroll. Documentation page: https://twblazor.com/on-this-page ## Basic usage Give `TwOnThisPage` a list of `OnThisPageItem`s, each pairing the `Id` of an element on the page with the text of its link. The link to the section being read is highlighted as the page scrolls. The example lists this page's own sections, so scroll the page to see it follow along. It is the same component as the "On this page" list beside every page of these docs. ```razor ``` ```csharp private readonly List _sections = [ new("basic-usage", "Basic usage"), new("link-paths", "Link paths"), new("title-and-heading-level", "Title and heading level"), new("hidden-title", "Hidden title"), new("fixed-headers", "Fixed headers") ]; ``` ## Link paths Every Blazor app has a ``, which makes a bare `#section` link point at the site root instead of the current page. Set `BasePath` to the current page's path so each link becomes `/your-page#section`. ```razor ``` ## Title and heading level The heading defaults to "On this page", translated into the app's language. Set `Title` to change it, and `HeadingLevel` so it fits the page's heading outline. The navigation landmark is named after the heading, so screen reader users can find it in their list of landmarks. ```razor ``` ## Hidden title Set `HideTitle` to leave the visible heading out, for example when the list sits under a heading of your own. The landmark keeps its name through `aria-label`, so it is still announced. ```razor ``` ## Fixed headers A section counts as the one being read once its top passes a line 140 pixels below the top of the viewport. Raise `Offset` when a fixed header covers more of the page than that, or lower it for a page with nothing fixed at the top. ```razor ``` ## Keyboard navigation The list is a navigation landmark holding ordinary links. The link to the section being read is announced as the current location. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves to the next or previous link. | | `Enter` | Jumps to the focused link's section. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwOnThisPage An "On this page" navigation list: a link to each section of the page, with the section currently being read highlighted as the page scrolls. | Parameter | Type | Description | | --- | --- | --- | | `Items` | `IReadOnlyList` | Gets or sets the sections to list, in the order they appear on the page. Each `Id` must be the DOM id of an element on the page. | | `Title` | `string?` | Gets or sets the heading shown above the links. Defaults to the localized "On this page". | | `HideTitle` | `bool` | Gets or sets whether the visible heading is left out. The navigation landmark is then named by `Title` through `aria-label` instead, so it is still announced. | | `HeadingLevel` | `int` | Gets or sets the heading level (1 to 6) of the title. Defaults to 2. Pick the level that fits the page's heading outline. | | `BasePath` | `string` | Gets or sets the path each link is relative to, e.g. `/docs/card`, giving links such as `/docs/card#usage`. | | `Offset` | `int` | Gets or sets the distance in pixels from the top of the viewport at which a section counts as the one being read. Raise it when a fixed header covers the top of the page. Defaults to 140. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwOnThisPageTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwOnThisPageTheme` by hand. --- # TwPagination > TwPagination is a Blazor pagination component. Bind ActivePage and PageSize, set TotalPages and ShowPageSize to split content across pages. Documentation page: https://twblazor.com/pagination ## Basic usage Bind `ActivePage` to track the current page as the user clicks between pages. `TotalPages` controls how many pages are available. ```razor

Page @activePage of 10

``` ```csharp private int activePage = 1; ``` ## Responding to page changes Use `ActivePageChanged` instead of two-way binding when you need to run logic - such as loading new data - whenever the page changes. ```razor

@pageChangedMessage

``` ```csharp private int pageChangedActivePage = 1; private string pageChangedMessage = "Showing results for page 1."; private void OnActivePageChanged(int page) { pageChangedActivePage = page; pageChangedMessage = $"Showing results for page {page}."; } ``` ## Dense Set `Dense` to render smaller, more compact buttons, useful for tight layouts such as beneath a table. The optional page size selector becomes dense too. ```razor ``` ```csharp private int denseActivePage = 1; private int densePageSize = 10; ``` ## Page size selector Set `ShowPageSize` to add an optional "items per page" dropdown alongside the pagination controls. Bind `PageSize` and customize `PageSizeOptions` to control the available choices. ```razor

Page @pageSizeActivePage of 12, showing @pageSize items per page.

``` ```csharp private int pageSizeActivePage = 1; private int pageSize = 10; ``` ## Keyboard navigation The pagination is a navigation landmark. The previous and next buttons stay focusable on the first and last page, where they are announced as unavailable. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves between the previous button, the page buttons, the next button and the page size list. | | `Enter` or `Space` | Goes to that page. The new page number is announced. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwPagination | Parameter | Type | Description | | --- | --- | --- | | `ActivePage` | `int` | Gets and sets the current active page. | | `TotalPages` | `int` | The total count of pages displayed. | | `ActivePageChanged` | `EventCallback` | The bound event callback when the active page is changed. | | `ShowPageSize` | `bool` | Whether to show an optional "items per page" dropdown alongside the pagination controls. | | `PageSize` | `int` | The number of items displayed per page. Only used when `ShowPageSize` is true. | | `PageSizeChanged` | `EventCallback` | The bound event callback when the page size is changed e.g. from displaying 5 per page to 10 etc. | | `PageSizeOptions` | `int[]` | The selectable options for `PageSize`. | | `Dense` | `bool` | Whether to render smaller, more compact buttons. | | `AnnouncePageChanges` | `bool` | Gets or sets whether a page change is announced to screen readers ("Page 2 of 5"). Turn it off when whatever hosts the pagination announces the change itself, so it is not read out twice. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwPaginationTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwPaginationTheme` by hand. --- # TwPickList > TwPickList is a Blazor dual list-box component for moving items between SourceItems and TargetItems, with move-all buttons, AllowReorder and keyboard support. Documentation page: https://twblazor.com/pick-list ## Basic usage Bind `SourceItems` and `TargetItems` to move items between the two lists. Click an item (or press Enter/Space) to select it, then use the chevron buttons to transfer the selection. ```razor ``` ```csharp private IEnumerable availableFruits = ["Apple", "Banana", "Cherry", "Mango", "Peach"]; private IEnumerable selectedFruits = ["Strawberry", "Blueberry"]; ``` ## Complex objects Use `TextField` to display a specific property when binding to a list of complex objects, matching `TwSelect`'s `PropertyName`. ```razor ``` ```csharp private sealed class Employee { public int Id { get; set; } public string Name { get; set; } = string.Empty; } private IEnumerable employees = [ new() { Id = 1, Name = "Alice Johnson" }, new() { Id = 2, Name = "Bob Smith" }, new() { Id = 3, Name = "Carol Lee" } ]; private IEnumerable developers = [ new() { Id = 4, Name = "David Kim" }, new() { Id = 5, Name = "Priya Patel" } ]; ``` ## Without reordering or move-all Set `AllowReorder="false"` to hide the up/down buttons, or `ShowMoveAllButtons="false"` to hide the double-chevron transfer-all buttons. ```razor ``` ## Disabled Set `Disabled` to prevent selection, transferring, and reordering. ```razor ``` ## Keyboard navigation Each list is a single Tab stop. Select items in a list, then use the buttons between the lists to move them. Every move is announced. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves between the two lists and the buttons. | | `Arrow Up` or `Arrow Down` | Moves to the previous or next item in the list. | | `Home` or `End` | Moves to the first or last item in the list. | | `Space` or `Enter` | Selects the focused item, or clears its selection. | | `Enter` or `Space` | On a button: moves the selected items across, moves every item across, or moves the selection up or down. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwPickList Represents a dual list-box ("pick list") that moves items between a source and a target collection, with two-way binding on both lists plus optional up/down reordering within either one. | Parameter | Type | Description | | --- | --- | --- | | `SourceItems` | `IEnumerable` | Gets or sets the items available in the source (left) list. | | `SourceItemsChanged` | `EventCallback>` | Gets or sets the callback invoked when items move into or out of the source list, or are reordered within it. | | `TargetItems` | `IEnumerable` | Gets or sets the items in the target (right) list. | | `TargetItemsChanged` | `EventCallback>` | Gets or sets the callback invoked when items move into or out of the target list, or are reordered within it. | | `SelectedSourceItems` | `IEnumerable` | Gets or sets the source list's initially selected items. Only read once, at first render - see the remarks on `TwPickList`. | | `SelectedSourceItemsChanged` | `EventCallback>` | Gets or sets the callback invoked whenever the source list's selection changes. | | `SelectedTargetItems` | `IEnumerable` | Gets or sets the target list's initially selected items. Only read once, at first render - see the remarks on `TwPickList`. | | `SelectedTargetItemsChanged` | `EventCallback>` | Gets or sets the callback invoked whenever the target list's selection changes. | | `TextField` | `string` | Gets or sets the name of the property to display for each item. | | `SourceLabel` | `string?` | Gets or sets the heading shown above the source list. Defaults to the localized `PickList_Source` text ("Available"). | | `TargetLabel` | `string?` | Gets or sets the heading shown above the target list. Defaults to the localized `PickList_Target` text ("Selected"). | | `EmptyText` | `string?` | Gets or sets the text shown in place of a list that has no items. Defaults to the localized `PickList_Empty` text ("No items"). | | `Disabled` | `bool` | Gets or sets whether the whole component is disabled. | | `ShowMoveAllButtons` | `bool` | Gets or sets whether the "move all" (double chevron) buttons are shown alongside the single-transfer chevron buttons. | | `AllowReorder` | `bool` | Gets or sets whether each column shows up/down buttons for reordering its current selection. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwPickListTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwPickListTheme` by hand. --- # TwProgress > TwProgress is a Blazor progress bar component. Set Value, Max, Color and Size, or use Indeterminate mode when the duration is unknown. Documentation page: https://twblazor.com/progress ## Basic usage A styled wrapper around the native `` element - it keeps the built-in `progressbar` role and automatic `aria-valuenow`/`aria-valuemin`/`aria-valuemax` semantics for free. ```razor ``` ## Colors Use `Color` to give a progress bar meaning at a glance - here it signals status rather than just decoration. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color))).Take(10)) { @if (c != Color.Light && c != Color.Dark) {
} else {
} } ``` ## Sizes Use `Size` to control the bar's thickness. ```razor
``` ## Indeterminate Set `Indeterminate` when the completion amount isn't known yet - the `value` attribute is omitted so it renders (and is announced) as busy rather than "0% done". ```razor ``` ## Animated Set `Animated` to sweep a shimmer across the filled portion of the bar while work is ongoing. It is decorative only - the announced value is unchanged - and it is switched off for users who prefer reduced motion. ```razor ``` ## Interactive Drive `Value` from your own component state - there's no built-in user interaction, so the bar only moves when your code updates it. ```razor

@uploadValue% complete

Upload next chunk ``` ```csharp private int uploadValue = 20; private void Advance() => uploadValue = Math.Min(100, uploadValue + 20); ``` ## Disabled Use `Disabled` to dim a progress bar that's paused or inactive. ```razor ``` ## Keyboard navigation A progress bar is not interactive and is not a Tab stop. Screen readers announce its label and value, or that it is busy when it is indeterminate. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwProgress Represents a generic progress bar that displays completion of a task towards a maximum value. | Parameter | Type | Description | | --- | --- | --- | | `Value` | `T` | Gets or sets the current value of the progress bar. | | `Max` | `T` | Gets or sets the value that represents 100% completion. | | `Indeterminate` | `bool` | Gets or sets whether the progress bar shows an indeterminate (unknown-duration) animation instead of a specific `Value`. | | `Animated` | `bool` | Gets or sets whether a shimmer animation sweeps across the filled portion of the progress bar to show that work is ongoing. | | `Color` | `Color?` | Gets or sets the color of the progress bar's filled portion. | | `Size` | `ProgressSize` | Gets or sets the size (thickness) of the progress bar. | | `AriaDescribedBy` | `string` | Gets or sets the id(s) of element(s) that describe the progress bar for assistive technology, in addition to any error message id. | | `AriaBusy` | `bool?` | Gets or sets whether the progress bar's region is announced as busy to assistive technology. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwProgressTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwProgressTheme` by hand. --- # TwQrCode > TwQrCode is a Blazor QR code component with no third-party dependencies. Set Value, ErrorCorrection, Size and QuietZone, or build codes with ITwQrCodeService. Documentation page: https://twblazor.com/qr-code ## Basic usage Give `TwQrCode` a `Value`, such as a URL, and it draws a QR code for it. The code is a single SVG path, so it stays sharp at any size. ```razor ``` ## Live value The code is only rebuilt when the `Value` or an encoding setting changes, so it is cheap to bind to an input. Nothing is drawn while the value is empty or too long to fit. ```razor
``` ```csharp private string liveValue = "https://twblazor.com"; ``` ## Error correction QR codes carry extra recovery data, so they still scan when part of the code is dirty, damaged or covered. `ErrorCorrection` sets how much: `Low` recovers about 7% of the code, `Medium` (the default) about 15%, `Quartile` about 25% and `High` about 30%. More recovery data means a denser code for the same text. Use `Medium` on screens, and `Quartile` or `High` for printed codes that may get worn. By default the level is raised for free whenever that does not make the code any denser; set `BoostErrorCorrection="false"` to keep exactly the level you chose. ```razor
@foreach (var level in Enum.GetValues()) {
@level
}
``` ## Sizes Use `Size` to set the dimensions. Every module scales with it, so a longer value packs smaller modules into the same space; give dense codes more room so they are easy to scan. ```razor
``` ## Quiet zone and shape Scanners find a code by the plain margin around it, called the quiet zone. `QuietZone` sets it in modules and defaults to 4, the minimum the standard asks for. Only reduce it when the code already sits on a plain light background. `Rounded` and `Shadow` style the outer edge. ```razor
``` ## Describing the code By default the code is announced as "QR code: " followed by its value. Set `AriaLabel` to say what scanning it does instead, and always show the link or text beside the code, so people without a camera can use it too. ```razor

Scan to read the guide, or go to twblazor.com/get-started.

``` ## Colors and dark mode The modules are drawn in the current text color over a background, both set by `Foreground` and `Background` in `TwQrCodeTheme`, the same settings the barcode uses. By default the code is black on white, and in dark mode it turns light on the page's own background. Most phone camera apps read these inverted symbols, but some dedicated scanners do not: to keep a code dark on light in dark mode, set `Background` to `bg-white` and `Foreground` to `text-black` in your theme, or override a single code with `Class`. Whatever colors you choose, keep strong contrast between them. ```razor
``` ## Using the service `ITwQrCodeService` is registered by `AddTwBlazor`. Call it directly to build a code outside a component: `Encode` returns a `QrMatrix` of dark and light modules. Draw it with the shared `SymbolSvg` methods from `TwBlazor.Services.Encoding`, which draw barcodes too: `ToSvg` writes a standalone SVG for a file, an email or inline markup, `ToSvgDataUri` gives a download link or image source, and `GetSvgPath` gives the path data for your own markup. `TryEncode` tells you whether a value fits without throwing. ```razor
@((MarkupString)serviceSvg)

Version @serviceMatrix.Version, @serviceMatrix.Size x @serviceMatrix.Size modules, @serviceMatrix.ErrorCorrection error correction.

``` ```csharp private const string serviceValue = "https://twblazor.com/qr-code"; private QrMatrix serviceMatrix = null!; private string serviceSvg = string.Empty; private string serviceDataUri = string.Empty; protected override void OnInitialized() { serviceMatrix = QrCodeService.Encode(serviceValue, new QrEncodeOptions { ErrorCorrection = QrErrorCorrection.Quartile }); var svgOptions = new SymbolSvgOptions { Title = $"QR code: {serviceValue}" }; serviceSvg = serviceMatrix.ToSvg(svgOptions); serviceDataUri = serviceMatrix.ToSvgDataUri(svgOptions); } ``` ## Accessibility A QR code is exposed as an image (`role="img"`) named after the text it holds, or after `AriaLabel` or `AriaLabelledBy` when set, and it is not a Tab stop. Its colors opt out of forced colors mode (`forced-color-adjust: none`) because a recolored code may not scan. A code alone cannot be used by someone without a camera, so put the link or text it holds beside it. ## Keyboard navigation A QR code is not interactive and is not a Tab stop. Screen readers announce it as an image named after the text it holds, unless it is given a label of its own. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwQrCode Shows text, such as a URL, as a scannable QR code. | Parameter | Type | Description | | --- | --- | --- | | `ErrorCorrection` | `QrErrorCorrection` | Gets or sets the minimum share of the code that can be damaged or covered and still scan. | | `BoostErrorCorrection` | `bool` | Gets or sets whether to raise `ErrorCorrection` when that does not make the code any denser. | | `Size` | `QrCodeSize` | Gets or sets the size of the QR code. | | `Value` | `string?` | Gets or sets the value to encode. Nothing is rendered while it is empty or cannot be encoded. | | `QuietZone` | `int?` | Gets or sets the light margin around the symbol, in modules. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwQrCodeTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwQrCodeTheme` by hand. --- # TwRadioButton > TwRadioButton is a Blazor radio button component. Bind SelectedValue, set Color, Disabled and Horizontal, or generate a group from Items. Documentation page: https://twblazor.com/radio-button ## Basic usage Group radio buttons with `TwRadioGroup` and bind values with `@bind-SelectedValue`. ```razor

Selected: @shipping

``` ```csharp private string shipping = "standard"; ``` ## Colors TwRadioButton supports all the standard theme colors via the `Color` property. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color)))) { @if (c != Color.Light && c != Color.Dark) {
} else {
} } ``` ## Data-driven (automatic) Use `Items` and `@bind-Value` to generate radio buttons from a list. ```razor

Selected: @selectedSize

Rating: @rating / 5

``` ```csharp private string selectedSize = "medium"; private int rating = 3; private readonly List> _sizeItems = new() { new() { Label = "Small", Value = "small" }, new() { Label = "Medium", Value = "medium" }, new() { Label = "Large", Value = "large" }, new() { Label = "Extra Large", Value = "xl" } }; private readonly List> _ratingItems = new() { new() { Label = "⭐ Poor", Value = 1 }, new() { Label = "⭐⭐ Fair", Value = 2 }, new() { Label = "⭐⭐⭐ Good", Value = 3 }, new() { Label = "⭐⭐⭐⭐ Great", Value = 4 }, new() { Label = "⭐⭐⭐⭐⭐ Excellent", Value = 5 } }; ``` ## Horizontal layout & custom spacing Use `Horizontal` to arrange buttons side-by-side, or `Class="gap-4"` for custom spacing. ```razor

Selected: @payment

Selected: @billing

``` ```csharp private string payment = "credit"; private string billing = "monthly"; private readonly List> _paymentItems = new() { new() { Label = "Credit Card", Value = "credit" }, new() { Label = "PayPal", Value = "paypal" }, new() { Label = "Cryptocurrency", Value = "crypto" } }; ``` ## Disabled state Disable the entire group with the `Disabled` property. ```razor ``` ## Programmatic control Change the selection programmatically by updating the bound value. ```razor

Current plan: @dynamicPlan

``` ```csharp private string dynamicPlan = "free"; private readonly List> _planItems = new() { new() { Label = "Free - £0/month", Value = "free" }, new() { Label = "Basic - £9/month", Value = "basic" }, new() { Label = "Pro - £29/month", Value = "pro" }, new() { Label = "Enterprise - Contact us", Value = "enterprise" } }; ``` ## Keyboard navigation Radio buttons are native radio inputs. A group is a single Tab stop. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the group, onto the selected option, or the first option when none is selected. | | `Arrow Down` or `Arrow Right` | Moves to the next option and selects it. | | `Arrow Up` or `Arrow Left` | Moves to the previous option and selects it. | | `Space` | Selects the focused option when none is selected yet. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRadioButton Represents a generic radio button input component for Blazor that supports two-way data binding and customizable value types. | Parameter | Type | Description | | --- | --- | --- | | `Name` | `string` | Gets or sets the name associated with the radio button group. | | `Color` | `Color?` | Gets or sets the color of the radio button. | | `Value` | `T` | Gets or sets the current value of the parameter. | | `SelectedValue` | `T?` | Gets or sets the selected value for the radio button group. | | `SelectedValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the selected value changes. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwRadioGroup Represents a container component for grouping multiple `TwRadioButton` components together. | Parameter | Type | Description | | --- | --- | --- | | `ChildContent` | `RenderFragment?` | Gets or sets the content to display within the radio group. | | `Legend` | `string?` | Gets or sets the legend text for the radio group. | | `LegendClass` | `string?` | Gets or sets the CSS class for the legend element. | | `Horizontal` | `bool` | Gets or sets the orientation of the radio group. | | `Disabled` | `bool` | Gets or sets whether the entire radio group is disabled. | | `Name` | `string?` | Gets or sets the name for all radio buttons in the group. | | `Items` | `IEnumerable>?` | Gets or sets the collection of items to display as radio buttons (for automatic mode). | | `Value` | `T?` | Gets or sets the selected value. | | `ValueChanged` | `EventCallback` | Gets or sets the callback invoked when the selected value changes. | | `ItemColor` | `Color?` | Gets or sets the color for automatically generated radio buttons. | | `Invalid` | `bool` | Gets or sets whether the group as a whole is in an error state. | | `ErrorMessage` | `string` | Gets or sets the error message for the group. It is shown under the options when `Invalid` is set, announced when it appears, and read as the group's description. | | `Required` | `bool` | Gets or sets whether one of the options must be chosen. Announced by assistive technology. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwRadioButtonTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwRadioButtonTheme` by hand. --- # TwRating > TwRating is a Blazor star rating component. Bind Value, set Min and Max, rate in whole or half steps and swap in any icon. Documentation page: https://twblazor.com/rating ## Basic usage Bind `Value` with `@bind-Value`. The rating is a group of native radio inputs, so it is one Tab stop and the arrow keys change the value. ```razor

You rated it @stayRating out of 5.

``` ```csharp private double stayRating = 4; ``` ## Whole and half steps The type of `T` sets the precision: an integer rates in whole icons, while `double`, `decimal` or `float` rate in half icons. Hover over the first half of an icon to pick the half. ```razor

Value: @wholeRating

Value: @halfRating

``` ```csharp private int wholeRating = 3; private decimal halfRating = 3.5m; ``` ## Rounding A value between steps is displayed rounded to the nearest half, or whole, icon. Set `Rounding` to change how: `AwayFromZero` (the default) rounds to the nearest, `ToNegativeInfinity` always rounds down and `ToPositiveInfinity` always rounds up. The bound value is never rewritten. ```razor
``` ```csharp private readonly double _averageRating = 3.7; ``` ## Icons and colors Any `Icon` works: a half step clips the filled icon to half its width. Set `EmptyIcon` to an outline icon to give unfilled steps a different shape as well as a different color, and `Color` to change the fill. ```razor
``` ```csharp private double heartRating = 3.5; private double outlinedRating = 2.5; private int spiceLevel = 2; private double energyRating = 4; ``` ## Sizes Use `Size` to pick small, medium (the default) or large icons. ```razor
``` ```csharp private double sizeRating = 3.5; ``` ## Min & max `Max` sets the number of icons. `Min` is the lowest value that can be picked: while it is 0 the rating can be cleared by clicking the selected icon again, or by choosing No rating from the keyboard. ```razor

Value: @tenRating / 10

Value: @requiredRating

``` ```csharp private int tenRating = 7; private int requiredRating = 1; ``` ## Animation Hovering grows an icon slightly and picking a value makes the newly filled icons pop. Set `DisableAnimation` to turn both off. They are always off for anyone whose system asks for reduced motion. ```razor
``` ```csharp private double animatedRating = 3; ``` ## Disabled & readonly `Disabled` dims the rating and locks it. `ReadOnly` keeps its colors and is announced as a single image, such as "Rated 4.5 out of 5", which suits showing a review score. ```razor
``` ## Validation Set `Invalid` and `ErrorMessage` to show an error. The message is tied to the group with `aria-describedby`, so screen readers read it with the rating. ```razor ``` ```csharp private int orderRating; ``` ## Keyboard navigation A rating is a group of native radio inputs, one for each value, and is a single Tab stop. A read-only rating is not a Tab stop: screen readers announce it as an image named after its value. | Key | What it does | | --- | --- | | `Tab` | Moves focus into the rating, onto the selected value. | | `Arrow Right` or `Arrow Up` | Selects the next value, half an icon or a whole icon at a time. | | `Arrow Left` or `Arrow Down` | Selects the previous value. Going below the first value selects No rating, when the rating can be cleared. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwRating Represents a rating input that shows a value as a row of icons, such as stars, and lets the user pick a new one. | Parameter | Type | Description | | --- | --- | --- | | `Value` | `T` | Gets or sets the current rating. | | `ValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the user picks a new rating. | | `Min` | `T` | Gets or sets the lowest rating the user can pick. Defaults to 0. | | `Max` | `T` | Gets or sets the highest rating, which is also the number of icons shown. Defaults to 5. | | `Rounding` | `MidpointRounding` | Gets or sets how a value between steps is rounded for display. Defaults to `AwayFromZero`, so 3.75 shows as 4 and 3.7 as 3.5. | | `Icon` | `Icon` | Gets or sets the icon drawn for each step. Defaults to `Star_Fill`. | | `EmptyIcon` | `Icon?` | Gets or sets the icon drawn behind the filled part, for the unfilled steps. Defaults to `Icon`, shown in a muted tint. | | `Color` | `Color?` | Gets or sets the color of the filled icons. Defaults to `Warning`. | | `Size` | `Size` | Gets or sets the size of the icons. Defaults to `Md`. | | `DisableAnimation` | `bool` | Gets or sets whether the hover growth and the "pop" played when a rating is picked are turned off. | | `Name` | `string` | Gets or sets the name shared by the rating's radio inputs. Defaults to the component's id. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwRatingTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwRatingTheme` by hand. --- # TwSelect > TwSelect is a Blazor select component for complex objects and numbers. Bind SelectedValue, or SelectedValues with Multiple, and set Placeholder and Required. Documentation page: https://twblazor.com/select ## Basic select Bind `SelectedValue` and use `Variant` to switch between default, filled and outlined styles. ```razor
@if (!string.IsNullOrEmpty(selectedCountry)) {

Selected Country: @selectedCountry

} ``` ```csharp private string selectedCountry = string.Empty; private readonly string[] _countries = ["USA", "Canada", "UK", "Germany", "France", "Japan", "Australia"]; ``` ## Desktop and mobile behavior On desktop, a single select opens an accessible listbox popover that you can drive with the arrow keys, `Home`, `End`, type-ahead and `Enter`. On iOS and Android it renders the browser's native `` on iOS and Android, so mobile/touch browsers still get their own platform multi-select UI rather than a bespoke one. ```razor @if (selectedSkills.Any()) {

Selected Skills: @string.Join(", ", selectedSkills)

} ``` ## Keyboard navigation The list opens below the field and focus moves into it. On a phone or tablet the browser's own picker is used. | Key | What it does | | --- | --- | | `Enter` or `Space` or `Arrow Down` or `Arrow Up` | Opens the list. | | `Arrow Up` or `Arrow Down` | Moves to the previous or next option. | | `Home` or `End` | Moves to the first or last option. | | `A to Z` | Moves to the next option starting with the typed letters. | | `Enter` or `Space` | Selects the focused option and closes the list. In a multiple select, adds or removes the option and keeps the list open. | | `Escape` or `Tab` | Closes the list without changing the value and returns focus to the field. | | `Enter` or `Space` | On a selected item's remove button in a multiple select: removes that item and returns focus to the field. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSelect Represents a generic select dropdown component that supports two-way data binding. | Parameter | Type | Description | | --- | --- | --- | | `Values` | `IEnumerable` | Gets or sets the collection of values to display in the dropdown. | | `SelectedValue` | `T` | Gets or sets the currently selected value. | | `SelectedValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the selected value changes. Choosing the placeholder clears the selection and passes `default`, such as `null` for a reference type. | | `Multiple` | `bool` | Gets or sets whether more than one option can be selected at once. | | `SelectedValues` | `IEnumerable` | Gets or sets the currently selected values when `Multiple` is `true`. | | `SelectedValuesChanged` | `EventCallback>` | Gets or sets the callback that is invoked when the selection changes while `Multiple` is `true`. | | `Placeholder` | `string?` | Gets or sets the placeholder text displayed when no value is selected. Defaults to the localized `Select_Placeholder` text ("Select an option..."). | | `Required` | `bool` | Gets or sets whether the select is required (no empty option will be shown). | | `PropertyName` | `string` | Gets or sets the name of the property to display for complex objects. | | `PreferNativePicker` | `bool?` | Overrides automatic device detection for whether the browser's native picker should be used instead of the custom popover. Leave unset (`null`) to auto-detect based on the client platform (iOS and Android use the native picker by default). | | `Variant` | `InputVariant?` | Gets or sets the visual variant of the input control (Default, Outlined, Filled). | | `Dense` | `bool` | Gets or sets whether the input uses a more compact height and text size, useful when screen space is limited. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwInputTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwInputTheme` by hand. --- # TwSidebar > TwSidebar is a Blazor sidebar for navigation. Build it from SidebarContent markup or data-driven NavigationItems, with IsSearchable and a collapsible layout. Documentation page: https://twblazor.com/sidebar ## Basic sidebar `TwSidebar` has all the functionality you'd want in a single component for a sidebar. You can customise the sidebar using both tailwind classes and additional TwBlazor Theme styling. ## Data-driven navigation (programmatic) Instead of hand-writing `SidebarContent` markup, pass a `List` to `NavigationItems` and TwSidebar renders the links, nested groups, and (with `IsSearchable`) a search box for you - this is exactly how this documentation site's own sidebar is built, see `Navigation.razor.cs`. Set `Icon` on a `NavigationItem` to render a `TwIcon` before its label. It works on links and parent items at any depth. The icon is decorative and hidden from screen readers, so the label stays the item's name. It is styled by `NavigationItemIcon` on `TwSidebarTheme`. ## Item content Use `NavigationItemContent` to render your own content after the label of the items generated from `NavigationItems`, such as a badge or a count. The template is called for every item and receives the `NavigationItem` as its context, so render nothing for the items that need no extra content. This documentation site uses it for the "New" badges in its own sidebar. It works on parent items as well as links: on a parent item the content sits between the label and the chevron, as on "Content" below. A badge on a parent can stand for everything inside it, in place of a badge on every child. Identify items by their `Id` or `Href`, not by reference, because the template receives a copy of the item while the sidebar is being searched. The content is placed inside the item's link or toggle button, so keep it non-interactive; any text in it is read out as part of the item's name. The wrapper around the content is styled by `NavigationItemContent` on `TwSidebarTheme`. ## Keyboard navigation The first Tab stop on the page is a link that skips the navigation. A closed sidebar is taken out of the Tab order entirely. On a narrow screen the sidebar opens over the page as a drawer: focus moves into it and the page behind it cannot be reached until it closes. | Key | What it does | | --- | --- | | `Tab` | From the top of the page: shows the "Skip to main content" link. | | `Enter` | On the skip link: moves focus to the main content. | | `Enter` or `Space` | On the sidebar button: opens or closes the sidebar. | | `Tab` or `Shift + Tab` | Moves through the search field and the navigation items. | | `Enter` or `Space` | On a group: expands or collapses it. | | `Enter` | On a link: goes to that page. | | `Escape` | Closes the sidebar while it is open as a drawer, from wherever focus is, and returns focus to the sidebar button. In the search field the first press clears the text. | | `Enter` or `Space` | On the close button inside the drawer: closes it. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSidebar Represents a responsive sidebar layout component with customizable header, navbar, and sidebar content areas. | Parameter | Type | Description | | --- | --- | --- | | `IsSidebarOpen` | `bool` | Gets or sets a value indicating whether the sidebar is currently open. | | `IsSidebarOpenChanged` | `EventCallback` | Gets or sets the callback that is invoked when the sidebar open state changes. | | `IsSearchable` | `bool` | Binds the searchable state of the sidebar, allows for sidebar items to be searched. | | `SearchLabel` | `string?` | Gets or sets the accessible name of the sidebar's search field, shown when `IsSearchable` is set. Defaults to the localized `Sidebar_SearchLabel` text ("Search navigation"). | | `ChildContent` | `RenderFragment?` | The page body content. | | `HeaderContent` | `RenderFragment?` | Gets or sets the content to render in the header area of the sidebar. | | `NavbarContent` | `RenderFragment?` | Gets or sets the content to be rendered in the navbar area of the component. | | `NavbarBrandContent` | `RenderFragment?` | Gets or sets the content rendered in the embedded navbar's brand slot. | | `NavbarNavigationContent` | `RenderFragment?` | Gets or sets custom content rendered in the embedded navbar in place of `NavbarNavigationItems`. | | `NavbarActionsContent` | `RenderFragment?` | Gets or sets the content rendered in the embedded navbar's actions slot. | | `NavbarNavigationItems` | `List` | Gets or sets the navigation items rendered in the embedded navbar when `NavbarNavigationContent` is not supplied. | | `SidebarContent` | `RenderFragment?` | Gets or sets the content to be rendered in the sidebar area of the component. | | `NavigationItems` | `List` | Gets or sets the collection of sidebar items to be displayed in the component. | | `NavigationItemContent` | `RenderFragment?` | Gets or sets the content rendered after the label of each item generated from `NavigationItems`, such as a badge or a count. | | `SidebarClass` | `string` | The classes that are applied to the parent div for the sidebar. | | `NavbarClass` | `string` | The classes that are applied to the parent div for the navbar. | | `ToggleButtonClass` | `string` | The classes that are applied to the toggle snackbar. | | `MainContentClass` | `string` | The classes that are applied to the main content div. | | `MainContentRootClass` | `string` | The classes that are applied to the main content root div. | | `IsNavbarFixed` | `bool` | Gets or sets a value indicating whether the navbar should be fixed at the top. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwSidebarTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwSidebarTheme` by hand. --- # TwSkeleton > TwSkeleton is a Blazor loading placeholder. Choose a SkeletonType and Animation, set Width and Height, or generate one from ChildContent while Loading. Documentation page: https://twblazor.com/skeleton ## Basic usage With no `ChildContent`, `TwSkeleton` renders a single full-width text line placeholder by default. ```razor ``` ## Shapes Use `SkeletonType` for a circle or rectangle placeholder instead, and `Width`/`Height` to size it. ```razor
``` ## Animation Use `Animation` to switch between a soft opacity pulse (default), a shimmering wave sweep, or no animation at all. ```razor
``` ## Auto-generated from content Wrap real markup in `ChildContent` and toggle `Loading` - while loading, `TwSkeleton` measures the actual rendered layout of that content (via a `ResizeObserver`) and generates matching placeholder blocks automatically, instead of a single generic box. ```razor @(loading ? "Finish loading" : "Reset")

Jane Doe

Product Designer

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

``` ```csharp private bool loading = true; private void ToggleLoading() => loading = !loading; ``` ## Keyboard navigation A skeleton is not interactive and is not a Tab stop. While it is showing, screen readers are told the content is loading. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSkeleton Renders a loading placeholder. With no `ChildContent` it renders a single static shape (`SkeletonType`/`Width`/`Height`). With `ChildContent` supplied, it instead measures the real rendered layout of that content (via the `twSkeleton.observe` JS interop call) and generates matching placeholder blocks automatically, so wrapping any markup in `` produces a skeleton shaped like the content it hides. | Parameter | Type | Description | | --- | --- | --- | | `Loading` | `bool` | Gets or sets whether the placeholder (or, with `ChildContent` supplied, a generated skeleton shaped like it) is shown instead of the real content. Default is `true`. | | `SkeletonType` | `SkeletonType` | Gets or sets the placeholder shape used when no `ChildContent` is supplied. Default is `Text`. | | `Animation` | `SkeletonAnimation` | Gets or sets the loading animation played by every placeholder block this component renders. Default is `Pulse`. | | `Width` | `string?` | Gets or sets a CSS width (e.g. `"50px"`, `"100%"`) for the standalone placeholder shape shown when no `ChildContent` is supplied. Ignored once `ChildContent` is set, since generated placeholders are sized from the content's own measured layout instead. | | `Height` | `string?` | Gets or sets a CSS height for the standalone placeholder shape. See `Width`. | | `ChildContent` | `RenderFragment?` | Gets or sets the real content to show once `Loading` is `false`. When supplied, this component ignores `SkeletonType`/`Width`/`Height` and instead generates placeholder blocks that mirror this content's own measured layout. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwSkeletonTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwSkeletonTheme` by hand. --- # TwSlider > TwSlider is a Blazor slider component for choosing a number in a range. Bind Value and set Min, Max, Step and Color. Documentation page: https://twblazor.com/slider ## Basic usage A drop-in replacement for `` with a fully custom, themeable track and thumb. ```razor

Current Volume: @volumeValue%

``` ```csharp private int volumeValue = 50; ``` ## Colors Use `Color` to give a slider meaning at a glance - here it signals status rather than just decoration. ```razor

@batteryValue% remaining

@cpuValue% load

@signalValue / 5 bars

``` ```csharp private int batteryValue = 82; private int cpuValue = 34; private int signalValue = 4; ``` ## Precision & range Any comparable numeric type works via `T` - use decimals with a fractional `Step` for fine control, or negative `Min` values for ranges that cross zero. ```razor

Selected Price: @($"${priceValue:F2}")

Set to: @temperatureValue°C

``` ```csharp private decimal priceValue = 25.50m; private int temperatureValue = 20; ``` ## Disabled & readonly `Disabled` dims and locks the slider; `ReadOnly` keeps its color but blocks changes. ```razor
``` ```csharp private int disabledValue = 40; private int readonlyValue = 70; ``` ## Keyboard navigation A slider is a native range input. A read-only slider can be focused but its value cannot be changed. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the slider. | | `Arrow Right` or `Arrow Up` | Increases the value by one step. | | `Arrow Left` or `Arrow Down` | Decreases the value by one step. | | `Home` or `End` | Sets the minimum or maximum value. | | `Pg.Up` or `Pg.Down` | Changes the value by a larger amount. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSlider Represents a generic slider component that enables users to select a value within a specified range. | Parameter | Type | Description | | --- | --- | --- | | `Value` | `T` | Gets or sets the current value of the parameter. | | `ValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the value changes. | | `Min` | `T` | Gets or sets the minimum allowed value for the parameter of type T. | | `Max` | `T` | Gets or sets the maximum allowable value for the parameter of type T. | | `Step` | `T` | Gets or sets the step value used to increment or decrement the slider's value. | | `Name` | `string` | Gets or sets the name associated with the component. | | `Color` | `Color?` | Gets or sets the color of the slider. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwSliderTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwSliderTheme` by hand. --- # TwSpinner > TwSpinner is a Blazor loading spinner component. Set Size, Color, Label and ShowLabel, or use it inside a button. Documentation page: https://twblazor.com/spinner ## Basic usage An animated loading indicator rendered as an `` element, so status changes are announced to assistive technology. The `Label` ("Loading..." by default) is always in the DOM for assistive technology, even when not shown visually. ```razor ``` ## Sizes Use `Size` to control the spinner's dimensions. ```razor
``` ## Colors Use `Color` to match the spinner to its surrounding context. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color))).Take(10)) { @if (c != Color.Light && c != Color.Dark) {
} else {
} } ``` ## Visible label By default the label text is only announced to assistive technology. Set `ShowLabel` to display it next to the spinner too. ```razor
``` ## Inside a button A common pattern: swap a button's label for a small spinner while an async action is in flight. ```razor @if (isSaving) { } else { @: Save changes } ``` ```csharp private bool isSaving; private async Task Save() { isSaving = true; await Task.Delay(1500); isSaving = false; } ``` ## Keyboard navigation A spinner is not interactive and is not a Tab stop. Screen readers announce its label when it appears. ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSpinner Represents an animated loading indicator. | Parameter | Type | Description | | --- | --- | --- | | `Color` | `Color?` | Gets or sets the color of the spinning arc. | | `Size` | `SpinnerSize` | Gets or sets the size of the spinner. | | `Label` | `string?` | Gets or sets the text announced to assistive technology while the spinner is visible. Defaults to the localized `Common_LoadingEllipsis` text ("Loading..."). | | `ShowLabel` | `bool` | Gets or sets whether `Label` is displayed visibly next to the spinner, instead of only being announced to assistive technology. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwSpinnerTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwSpinnerTheme` by hand. --- # TwStepper > TwStepper is a Blazor stepper for multi-step flows. Bind ActiveStepIndex, set Orientation, Linear and Color, and give each step a Label and Description. Documentation page: https://twblazor.com/stepper ## Basic stepper Add `TwStep` children to a `TwStepper` to declare each step, and bind `ActiveStepIndex` to control which one is active. Wire your own "Back"/"Next" buttons to a component reference's `PreviousStep()` and `NextStep()` methods, as shown below. Below the "sm" breakpoint the step row automatically collapses into a compact progress bar with a "Step X of N" label, so try resizing your browser to see it adapt. ```razor

Enter your email address and choose a password.

Enter the shipping address for your order.

Review your order details before confirming payment.

``` ```csharp private TwStepper basicStepper = null!; private int basicActiveStep; ``` ## Validating a step Pass your own validation `Task` to a "Next" button's click handler and only call `NextStep` when it passes - the stepper doesn't need to know anything about your validation logic. ```razor

Thanks, @signupEmail is confirmed!

``` ```csharp private TwStepper validatedStepper = null!; private int validatedActiveStep; private string signupEmail = string.Empty; private bool emailInvalid; private Task ValidateAndContinue() { emailInvalid = string.IsNullOrWhiteSpace(signupEmail) || !signupEmail.Contains('@'); return emailInvalid ? Task.CompletedTask : validatedStepper.NextStep(); } ``` ## Non-linear stepper Set `Linear="false"` to let users jump straight to any non-disabled step by clicking it, instead of only being able to reach steps they've already visited. ```razor ``` ## Disabled step Set `Disabled` on a `TwStep` to prevent it from being navigated to, whether by clicking or via `NextStep`/`PreviousStep` (which both skip over it). ```razor ``` ## Vertical stepper Set `Orientation="StepperOrientation.Vertical"` to stack steps top-to-bottom, with each step's content shown inline beneath its label while it's active. ```razor

Choose a username and password to get started.

We've sent a confirmation link to your inbox.

You're all set!

``` ```csharp private TwStepper verticalStepper = null!; private int verticalActiveStep; ``` ## Colored stepper Set `Color` to change the accent used for the active and completed step indicators and connectors. ```razor ``` ## Keyboard navigation The steps are a navigation landmark. Each step you can go to is a button, and the step you land on is announced. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves between the steps you can go to. In a linear stepper those are the current step and the ones before it. | | `Enter` or `Space` | Goes to the focused step. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwStepper Represents a step-by-step progress indicator for multi-step flows (e.g. checkout, onboarding wizards), showing which steps are completed, which is active, and which are still upcoming. | Parameter | Type | Description | | --- | --- | --- | | `ActiveStepIndex` | `int` | Gets or sets the index (zero-based) of the currently active step. | | `ActiveStepIndexChanged` | `EventCallback` | Gets or sets the callback invoked when the active step changes, enabling two-way binding via `@bind-ActiveStepIndex`. | | `Linear` | `bool` | Gets or sets whether steps must be completed in order. | | `Orientation` | `StepperOrientation` | Gets or sets the layout direction of the stepper. | | `Color` | `Color?` | Gets or sets the accent color used for the active and completed step indicators and connectors. | | `ChildContent` | `RenderFragment` | Gets or sets the `TwStep` children declaring each step. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwStep Represents a single step within a `TwStepper`. | Parameter | Type | Description | | --- | --- | --- | | `Label` | `string` | Gets or sets the label displayed for this step. | | `Description` | `string?` | Gets or sets a short secondary description shown beneath the label (e.g. "Optional"). | | `Disabled` | `bool` | Gets or sets whether this step is disabled and cannot be navigated to. | | `Icon` | `Icon?` | Gets or sets an icon to display in the step's indicator instead of its step number, while the step is active or upcoming. A completed step always shows a checkmark regardless of this value. | | `ChildContent` | `RenderFragment?` | Gets or sets optional content for this step. On `Horizontal`, it is rendered in a shared panel below the step row while this step is active; on `Vertical`, it is rendered inline beneath this step's label while this step is active. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwStepperTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwStepperTheme` by hand. --- # TwSwitch > TwSwitch is a Blazor toggle switch component for on and off settings. Bind Value and set Color, Name, and disabled or readonly states. Documentation page: https://twblazor.com/switch ## Basic usage A toggle switch for binary on/off state, bound with `@bind-Value`. ```razor

Notifications are @(notificationsEnabled ? "on" : "off")

``` ```csharp private bool notificationsEnabled = true; ``` ## Colors Use `Color` to give a switch meaning at a glance - here each toggle drives an independent, bound setting. ```razor @foreach (Color c in ((Color[])Enum.GetValues(typeof(Color))).Take(10)) { @if (c != Color.Light && c != Color.Dark) {
} else {
} } ``` ## Disabled & readonly `Disabled` dims and locks the switch; `ReadOnly` keeps its state and color but blocks changes. ```razor
``` ```csharp private bool disabledValue = false; private bool readonlyValue = true; ``` ## Settings panel A practical example - each switch binds to its own field, and a summary below reflects the combined state. ```razor

Active settings:

@if (activeSettings.Count > 0) {
    @foreach (var setting in activeSettings) {
  • @setting
  • }
} else {

None enabled

}
``` ```csharp private bool emailNotifications = true; private bool smsNotifications = false; private bool marketingEmails = false; private List activeSettings { get { var settings = new List(); if (emailNotifications) settings.Add("Email notifications"); if (smsNotifications) settings.Add("SMS notifications"); if (marketingEmails) settings.Add("Marketing emails"); return settings; } } ``` ## Keyboard navigation A switch is announced as a switch that is on or off. A read-only switch can be focused but not changed. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the switch. | | `Space` | Turns it on or off. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwSwitch Represents a toggle switch component that allows users to select between two states. | Parameter | Type | Description | | --- | --- | --- | | `Name` | `string` | Gets or sets the name associated with the component. | | `Color` | `Color?` | Gets or sets the color of the switch. | | `Value` | `T` | Gets or sets the current value of the parameter. | | `ValueChanged` | `EventCallback` | Gets or sets the callback that is invoked when the value changes. | | `RootId` | `string` | Gets or sets the unique identifier for the root element. | | `RootClass` | `string` | Gets or sets the CSS class name applied to the root element of the component. | | `RootAttributes` | `Dictionary` | Gets or sets the additional attributed applied to the root element of the component. | | `Label` | `string` | Gets or sets the text label associated with the component. | | `LabelId` | `string` | Gets or sets the unique identifier for the associated label element. | | `LabelAttributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the label element. | | `LabelClass` | `string` | Gets or sets the classes for the label. | | `ReadOnly` | `bool` | Gets or sets whether the input component is readonly. | | `Disabled` | `bool` | Gets or sets whether the input component is disabled. | | `Invalid` | `bool` | Gets or sets whether the input component currently fails validation. | | `ErrorMessage` | `string` | Gets or sets the validation error message to display and associate with the input. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwSwitchTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwSwitchTheme` by hand. --- # TwTable > TwTable is a Blazor table component with striped, hoverable, bordered and borderless styles, plus manual pagination. Documentation page: https://twblazor.com/table ## Basic table A simple table component with customizable styling. ```razor Product name Color Category Price Apple MacBook Pro 17" Silver Laptop £2999 Microsoft Surface Pro White Laptop PC £1999 Magic Mouse 2 Black Accessories £99 ``` ## Striped table Table with alternating row colors for better readability. ```razor Name Department Role John Doe Engineering Developer Jane Smith Product Designer Bob Johnson Operations Manager ``` ## Hoverable table Table with hover effects on rows. ```razor Task Status Priority Design homepage In Progress High Write documentation Completed Medium Fix bugs Pending High ``` ## Bordered table Table with a hairline divider between rows, for extra structure without a busy grid look. ```razor Country Capital Population United States Washington, D.C. 331 million United Kingdom London 67 million Germany Berlin 83 million ``` ## Table without border Table with no outer border. ```razor Country Capital Population United States Washington, D.C. 331 million United Kingdom London 67 million Germany Berlin 83 million ``` ## Column widths Add a `ColumnGroup` of `TwTableColumn` elements to size the columns. A column with a `Width` never goes narrower than it, so a long description in one column cannot squeeze a short name or a code value in another. Columns without a width share the space that is left. `Width` takes any CSS length and needs no Tailwind class, and `Span` lets one definition cover several columns. ```razor Command What it does dotnet add package TwBlazor Adds the component library to your project, along with the default theme and the scripts the interactive components need. dotnet build Builds the project and runs the Tailwind build, so every class the theme uses is compiled into your stylesheet. ``` ## Fixed layout By default the browser sizes each column from its content. Set `FixedLayout` and the widths come from the column group and the header row instead, so the columns stay put however long the content in a row is. This suits tables whose rows change as you page or filter them. Long content wraps inside its column. ```razor Owner Due Notes Jane Smith 14/11/2026 Write the onboarding guide for new starters, covering accounts, equipment and the first week. Bob Johnson 21/11/2026 Review supplier contracts. ``` ## Scrolling with a sticky header Set `MaxHeight` to any CSS length and the rows scroll inside the table once it is that tall. Add `StickyHeader` to keep the column headings in view while they scroll. The scroll area is a Tab stop, so the rows can be scrolled with the arrow keys too. ```razor Month Orders Revenue @foreach (var (month, orders, revenue) in _monthlySales) { @month @orders £@revenue.ToString("N0") } ``` ```csharp private static readonly (string Month, int Orders, int Revenue)[] _monthlySales = [ ("January", 412, 18_240), ("February", 389, 17_115), ("March", 455, 20_380), ("April", 431, 19_020), ("May", 478, 21_660), ("June", 502, 23_010), ("July", 466, 20_940), ("August", 441, 19_580), ("September", 497, 22_430), ("October", 523, 24_105), ("November", 610, 28_870), ("December", 688, 33_215) ]; ``` ## Row groups Use `RowGroups` in place of `TableBody` to split the rows into groups, each in its own ``. The context is the body's classes, so put it on every `` and the groups keep the striped, hoverable and bordered styles. Start each group with a header cell that has `scope="rowgroup"`, and screen readers announce the group's name with every row in it. ```razor Name Role Engineering John Doe Developer Alice Williams Developer Product Jane Smith Designer ``` ## Typed rows Put a `TwTableRows` in `TableBody`, give it your rows with `Items`, and write one row in it. The context is the row's item, so the row is typed. On its own it renders every row, and it is what lets the table page or virtualize them, below. ```razor Product name Category Price @product.Name @product.Category £@product.Price.ToString("N0") ``` ```csharp private int productPage = 1; private readonly List _products = [ new("Apple MacBook Pro 17\"", "Laptop", 2999), new("Microsoft Surface Pro", "Laptop", 1999), new("Magic Mouse 2", "Accessories", 99), new("Apple Watch Series 9", "Wearables", 499), new("iPad Air", "Tablet", 799), new("Samsung Galaxy S24", "Phone", 1199), new("Sony WH-1000XM5", "Accessories", 399), new("AirPods Pro", "Accessories", 249) ]; public record Product(string Name, string Category, int Price); ``` ## Pagination Set `EnablePagination` and the table splits its `TwTableRows` into pages, with a pagination below it. Pagination is off by default. `PageSize` sets the rows on a page and `PageSizeOptions` the sizes people can pick; bind `@bind-CurrentPage` to follow or set the page. If the rows shrink under the current page, as after a search, the table moves back to the last page and raises `CurrentPageChanged`. ```razor Product name Category Price @product.Name @product.Category £@product.Price.ToString("N0")

Page @productPage

``` ```csharp private int productPage = 1; private readonly List _products = [ new("Apple MacBook Pro 17\"", "Laptop", 2999), new("Microsoft Surface Pro", "Laptop", 1999), new("Magic Mouse 2", "Accessories", 99), new("Apple Watch Series 9", "Wearables", 499), new("iPad Air", "Tablet", 799), new("Samsung Galaxy S24", "Phone", 1199), new("Sony WH-1000XM5", "Accessories", 399), new("AirPods Pro", "Accessories", 249) ]; public record Product(string Name, string Category, int Price); ``` ## Virtualization Set `EnableVirtualization` and only the rows scrolled into view are rendered, so the table stays fast with tens of thousands of rows. It is off by default. The rows scroll inside the table, which is `32rem` tall unless you set `MaxHeight`, and the header stays in view. Keep each row to one line, about `ItemSize` pixels tall. Write the row in `RowTemplate` and put its `AriaRowIndex` on the ``: the table then tells screen readers how many rows there are and where each one sits, so they still read "row 5000 of 10000". ```razor Reading Sensor Temperature @row.Item.Number @row.Item.Sensor @row.Item.Celsius.ToString("N1") °C ``` ```csharp private static readonly string[] _sensors = ["Kitchen", "Hall", "Garage", "Loft", "Garden"]; private readonly List _readings = [.. Enumerable.Range(1, 10_000).Select(i => new Reading(i, _sensors[i % _sensors.Length], Math.Round(15 + (i * 37 % 100) / 10.0, 1)))]; public record Reading(int Number, string Sensor, double Celsius); ``` ## Loading rows from a server For data too big to load at once, give `TwTableRows` an `ItemsProvider` in place of `Items`. With pagination it is asked for one page at a time, with virtualization for the rows scrolling into view, and otherwise for every row. It returns the rows and the total count, and receives a cancellation token that is cancelled when a newer request replaces it. While rows load the table is marked busy and shows `LoadingContent`. Call `RefreshDataAsync` on the rows after the data changes elsewhere. ```razor Reading Sensor Temperature @reading.Number @reading.Sensor @reading.Celsius.ToString("N1") °C Loading readings… ``` ```csharp // Stands in for a database query: in a real app, pass the request on to your API or Entity Framework. private async ValueTask> LoadReadingsAsync(TwTableRowsRequest request) { await Task.Delay(300, request.CancellationToken); var page = _readings.Skip(request.StartIndex).Take(request.Count ?? _readings.Count).ToList(); return new TwTableRowsResult(page, _readings.Count); } ``` ## Resizable columns Set `ResizableColumns` and define the columns with `TwTableColumn`. Each column then has a separator on the border at the end of its header: drag it, or focus it with `Tab` and press `Arrow Left` or `Arrow Right`, holding `Shift` for bigger steps. Screen readers hear each separator as "Resize Name" with the column's width. Give each column a `Label` to name its separator, `MinWidth` and `MaxWidth` to limit it, and `Resizable="false"` to keep it at its width. Resizing turns on `FixedLayout`, gives every column its current width in pixels so the others stay put, and raises `ColumnsResized` and each column's `WidthChanged`. ```razor Product name Category Price @product.Name @product.Category £@product.Price.ToString("N0")

@resizedWidths

``` ```csharp private string resizedWidths = "Resize a column to see its new width."; private void OnColumnsResized(IReadOnlyDictionary widths) => resizedWidths = string.Join(", ", widths.Select(w => $"{w.Key.Replace("resizable-", string.Empty)} {w.Value}")); ``` ## Keyboard navigation The table is read as a native table. Its scroll area is a Tab stop so a table wider or taller than its container can be scrolled from the keyboard. With ResizableColumns, each resizable column has a separator on its header's border that reports the column's width. | Key | What it does | | --- | --- | | `Tab` or `Shift + Tab` | Moves focus to the table's scroll area, then to each column's resize separator and the pagination. | | `Arrow Left` or `Arrow Right` or `Arrow Up` or `Arrow Down` or `Pg.Up` or `Pg.Down` | In the scroll area: scrolls the table. A virtualized table renders the rows as they scroll into view. | | `Arrow Left` or `Arrow Right` | On a resize separator: makes the column wider or narrower. The key moves the border the way it points, in either text direction. | | `Shift + Arrow Left` or `Shift + Arrow Right` | On a resize separator: resizes in bigger steps. | | `Enter` or `Space` | In the pagination: moves to a page, or opens the page size list. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwTable Represents a customizable table component for Blazor applications that enables rendering of table headers, body, and footers with configurable styling and behaviour. | Parameter | Type | Description | | --- | --- | --- | | `ResizableColumns` | `bool` | Whether people can resize the columns defined in `ColumnGroup` by dragging the border at the end of a column's header, or by focusing that border and pressing the arrow keys. Turns on `FixedLayout` so a column keeps the width it is given. Defaults to `false`. | | `ColumnsResized` | `EventCallback>` | Raised once a person finishes resizing, with the new width of every column, keyed by each `TwTableColumn`'s `Id`. | | `EnablePagination` | `bool` | Whether to split the rows of a `TwTableRows` inside the table into pages, with a `TwPagination` below the table. Defaults to `false`. Ignored while `EnableVirtualization` is set, since the rows then scroll instead. | | `CurrentPage` | `int` | Gets or sets the one based page shown when `EnablePagination` is set. Bind it with `@bind-CurrentPage` to follow or change the page. Defaults to `1`. | | `CurrentPageChanged` | `EventCallback` | Raised when the page changes, including when it moves back because the rows ran out. | | `PageSize` | `int` | Gets or sets how many rows a page holds when `EnablePagination` is set. Defaults to `10`. | | `PageSizeChanged` | `EventCallback` | Raised when a person picks a different page size. | | `PageSizeOptions` | `int[]` | Gets or sets the page sizes a person can pick from. Defaults to 5, 10, 25, 50 and 100. | | `ShowPageSize` | `bool` | Whether the pagination shows its page size list. Defaults to `true`. | | `ComfortablePagination` | `bool` | Whether the pagination uses regular size buttons instead of the default compact ones. Defaults to `false`. | | `AnnouncePageChanges` | `bool` | Whether the pagination announces the new page to screen readers. Defaults to `true`. Turn it off when you announce page changes yourself. | | `PaginationLabel` | `string?` | Gets or sets the accessible name of the pagination. Defaults to the localized `Table_Pagination` text ("Table pagination"). | | `EnableVirtualization` | `bool` | Whether to render only the rows of a `TwTableRows` that are scrolled into view, so a table of thousands of rows stays fast. The rows scroll inside the table, which is `MaxHeight` tall (`32rem` unless set), and the header stays in view. Defaults to `false`. | | `ItemSize` | `float` | Gets or sets the height of a row in pixels when `EnableVirtualization` is set, used to work out which rows are in view before they render. Defaults to `41`, the height of a row in the default theme. | | `OverscanCount` | `int` | Gets or sets how many extra rows to render above and below the ones in view when `EnableVirtualization` is set, so fast scrolling does not show gaps. Defaults to `5`. | | `HeaderRowCount` | `int` | Gets or sets how many rows the header holds, used to number the body rows for assistive technology when `EnableVirtualization` is set. Defaults to `1`. | | `ScrollRegionLabel` | `string?` | Gets or sets the accessible name of the scrollable region that wraps the table. Defaults to the localized `Table_ScrollRegion` text ("Scrollable table"). | | `Caption` | `RenderFragment?` | Optional caption content for the table, rendered as a `` element. Provides an accessible name/description for the table that is programmatically associated with it. Visually hidden by default (via the `sr-only` class) unless `CaptionVisible` is set to `true`. | | `CaptionVisible` | `bool` | Whether the `Caption` should be visible. Defaults to `false`, rendering the caption visually hidden (but still available to assistive technology). | | `ColumnGroup` | `RenderFragment?` | Optional column definitions, rendered inside a `` before the table sections. Use `TwTableColumn` to give columns a width, so long or breakable content (such as inline code) cannot squeeze a column narrower than its content needs. | | `FixedLayout` | `bool` | Whether column widths come from the `ColumnGroup` and the header row instead of the cell content (CSS `table-layout: fixed`). Columns keep the same width however their content changes, which suits tables whose rows are paged, filtered or loaded on demand. Defaults to `false`. | | `MaxHeight` | `string?` | Gets or sets the tallest the table can grow before its rows scroll inside it, as any CSS length such as `24rem` or `60vh`. Leave it unset for the table to be as tall as its rows. Pair it with `StickyHeader` to keep the column headings in view. | | `StickyHeader` | `bool` | Whether the header row stays at the top of the table while its rows scroll beneath it. Only has an effect when the table scrolls, for example with `MaxHeight`. Defaults to `false`. | | `TableHeader` | `RenderFragment?` | Content to render in the table header (thead). | | `TableBody` | `RenderFragment?` | Content to render in the table body (tbody). | | `RowGroups` | `RenderFragment?` | Content made of several `` elements, one for each group of rows, rendered in place of `TableBody`. The context is the body's CSS classes (including `Striped`, `Hoverable` and `Bordered`), so put it on every `` to style the groups like a single body. Start each group with a header cell that has `scope="rowgroup"`, and assistive technology announces it with every row in the group. | | `TableFooter` | `RenderFragment?` | Content to render in the table footer (tfoot). | | `HeaderClass` | `string?` | Additional CSS classes for the header section. | | `BodyClass` | `string?` | Additional CSS classes for the body section. | | `FooterClass` | `string?` | Additional CSS classes for the footer section. | | `Striped` | `bool` | Whether to show striped rows. | | `Hoverable` | `bool` | Whether to show hover effect on rows. | | `Bordered` | `bool` | Whether to show borders on all cells. | | `NoBorder` | `bool` | Whether to hide the outer table border. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwTableColumn Defines one or more columns of a `TwTable`, rendered as a `` element inside the table's `ColumnGroup`. | Parameter | Type | Description | | --- | --- | --- | | `Resizable` | `bool` | Gets or sets whether people can resize this column when the table's `ResizableColumns` is set. Defaults to `true`. A column that spans several columns is never resizable. | | `Label` | `string?` | Gets or sets the column's name for assistive technology, used to name its resize border ("Resize Price"). Set it to the column's heading. | | `MinWidth` | `int` | Gets or sets the narrowest a person can make the column by resizing it, in pixels. Defaults to `48`. | | `MaxWidth` | `int` | Gets or sets the widest a person can make the column by resizing it, in pixels. Defaults to `2000`. | | `WidthChanged` | `EventCallback` | Raised with the column's new width, such as `180px`, after a person resizes it. Bind it with `@bind-Width` to keep the width. | | `Width` | `string?` | Gets or sets the width of the column as any CSS length, such as `12rem`, `160px` or `25%`. Leave it unset to size the column from the remaining space. | | `Span` | `int` | Gets or sets how many consecutive columns this definition covers. Defaults to `1`. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwTableRows The typed rows of a `TwTable`. Place it in the table's `TableBody` and give it the rows, and the table pages them (`EnablePagination`) or renders only the ones in view (`EnableVirtualization`). | Parameter | Type | Description | | --- | --- | --- | | `Items` | `IEnumerable?` | Gets or sets the rows. Leave it unset when `ItemsProvider` loads them instead. | | `ItemsProvider` | `TwTableRowsProvider?` | Gets or sets a function that loads rows on demand, such as from a database or an API, in place of `Items`. It is asked for one page at a time with `EnablePagination`, for each scrolled window with `EnableVirtualization`, and for every row otherwise. | | `ChildContent` | `RenderFragment?` | Gets or sets the markup for one row, a ``, given the row's item. | | `RowTemplate` | `RenderFragment>?` | Gets or sets the markup for one row, a ``, given the row's item, its place among all the rows, and the `aria-rowindex` to put on it. Use it in place of `ChildContent` with `EnableVirtualization`, so screen readers know where each rendered row sits. | | `PageTemplate` | `RenderFragment>?` | Gets or sets the markup for every row on the current page at once, in place of a template per row. Use it inside `RowGroups` to split a page into several `` elements. Not used with `EnableVirtualization`. | | `EmptyContent` | `RenderFragment?` | Gets or sets what to render when there are no rows, such as a row with a message. | | `LoadingContent` | `RenderFragment?` | Gets or sets what to render while `ItemsProvider` loads rows that are not on screen yet. | | `ItemsLoaded` | `EventCallback>` | Raised each time `ItemsProvider` returns rows, with the rows and the total count. | ## Theme Styled by `TwTableTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwTableTheme` by hand. --- # TwTabs > TwTabs is a Blazor tabs component, built from TwTabContainer and TwTab. Set Label, Color, Dense and Disabled, and colour the whole container or single tabs. Documentation page: https://twblazor.com/tabs ## Basic tabs Use `TwTabContainer` and `TwTab` to split content into switchable panels. ```razor

This is the content of Tab 1.

This is the content of Tab 2.

``` ## Container tab colors Set `TabColor` on `TwTabContainer` to choose the colour of the selected tab's label and underline. Unselected tabs stay neutral, so the selected tab is always the one that stands out. ```razor

Setting the TabColor property on the TwTabContainer sets the selected colour for every tab within that container.

This is the content of Tab 2.

This is the content of Tab 2.

``` ## Single tab colors Set `Color` on an individual `TwTab` to give just that tab its own selected colour. Select each tab below to see it. ```razor

Setting the Color property on an individual tab sets the colour it uses while it is selected.

This is the content of Tab 2.

This is the content of Tab 3.

``` ## Dense tabs Set `Dense` on `TwTabContainer` to render more compact tabs. ```razor

This is the content of Tab 1.

This is the content of Tab 2.

``` ## Disabled tabs Set `Disabled` on a `TwTab` to prevent it from being selected. ```razor

This is the content of Tab 1.

This is the content of Tab 2.

``` ## Keyboard navigation The tab list is a single Tab stop, and moving to a tab shows its panel straight away. Disabled tabs are skipped. In a right to left layout Arrow Left moves to the next tab and Arrow Right to the previous one. | Key | What it does | | --- | --- | | `Tab` | Moves focus to the selected tab, then to the tab panel, then on to the panel's content. | | `Arrow Right` or `Arrow Down` | Moves to the next tab and shows it. From the last tab it wraps to the first. | | `Arrow Left` or `Arrow Up` | Moves to the previous tab and shows it. From the first tab it wraps to the last. | | `Home` or `End` | Moves to the first or last tab. | ## Parameters This is every parameter the component accepts. Do not use parameters that are not listed here. ### TwTabContainer Represents a tabbed interface component that allows users to organize and switch between multiple content sections within a user interface. | Parameter | Type | Description | | --- | --- | --- | | `TabColor` | `Color?` | Gets or sets the color of all the tabs associated with the component. | | `Dense` | `bool` | Gets or sets whether the tabs should use dense (compact) styling with reduced padding. | | `ChildContent` | `RenderFragment` | Gets or sets the content to be rendered inside the component. | | `TabContainerClass` | `string?` | Gets or sets additional CSS classes for the tabs navigation container. | | `ContainerClass` | `string?` | Gets or sets additional CSS classes for the tab content area. | | `TransparentContainer` | `bool` | Gets or sets whether the background class should be removed from the tab navigation and content containers, leaving only the border outline. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ### TwTab Represents a tab within a tab container, allowing users to navigate between different content sections. | Parameter | Type | Description | | --- | --- | --- | | `Label` | `string` | The label to display for this tab. This is a required parameter and is used to identify the tab in the user interface. | | `ChildContent` | `RenderFragment` | The content to be displayed when this tab is active. This is a required parameter and should contain the markup or components that make up the tab's content. | | `Color` | `Color?` | The color of the tab's text and underline indicator while it is the active tab. If not specified, it will inherit the color from the parent tab container. | | `Disabled` | `bool` | Gets or sets a value indicating whether the component is disabled and cannot be interacted with by the user. | | `Id` | `string?` | Gets or sets the unique identifier for the component. | | `Class` | `string` | Gets or sets the CSS class(es) to apply to the component. | | `Style` | `string?` | Gets or sets inline CSS styles to apply to the component. | | `Attributes` | `Dictionary` | Gets or sets a collection of additional attributes to apply to the component. | | `AriaLabel` | `string?` | Gets or sets the ARIA label for accessibility. | | `AriaLabelledBy` | `string?` | Gets or sets the ID of another element that labels this component for accessibility. | | `Shadow` | `Shadow?` | Gets or sets the shadow (elevation) level for the component. | | `Rounded` | `Rounded?` | Gets or sets the border radius for the component. | ## Theme Styled by `TwTabTheme`. Include it by ticking this component on the Theme builder (https://twblazor.com/theme) and replacing `Theme.cs` with the newly generated file. Never write or edit `TwTabTheme` by hand. --- # Tailwind CSS with Blazor > How to use Tailwind CSS with Blazor Server and WebAssembly, and how twblazor gives you accessible, themeable Tailwind Blazor components. Documentation page: https://twblazor.com/tailwind-blazor ## Why Tailwind with Blazor? Tailwind CSS is a utility-first CSS framework: you style elements with small single-purpose classes such as `px-4` or `bg-purple-600` instead of writing stylesheets. Blazor renders Razor markup, so those classes sit directly in your components and your design lives next to the markup that uses it. The catch is that Tailwind only generates the classes it can find as literal text in your source files. That matters the moment a component library is involved, because Tailwind cannot read the classes compiled into a NuGet package's DLL. ## How Tailwind finds your classes Tailwind scans the files you point it at with `@source` directives and generates CSS for every class name it finds. In a Blazor project that means your `.razor` files and any C# file that holds class names. ```css @import "tailwindcss"; @source "../../**/*.razor"; @source "../../Theme.cs"; ``` Run the Tailwind CLI against that input file to produce `output.css`, then link it from `App.razor` (Blazor Server and Web App) or `index.html` (standalone WebAssembly). Nothing about Tailwind needs a Node server at runtime, only at build time. ## How twblazor handles the DLL problem twblazor is a Tailwind Blazor component library, so it solves the problem above directly. Every class a component uses is declared as a literal string in a `Theme.cs` file that lives in **your** project. Your Tailwind build scans that file alongside your Razor files and produces one stylesheet containing everything. ```csharp builder.Services.AddTwBlazor(_ => { }, Theme.CreateDefaultTheme); ``` Because the classes are plain C# strings in your own code, you can change a component's look by editing one property, with no CSS overrides and no `!important`. The [Theme builder](https://twblazor.com/theme) generates a `Theme.cs` with your brand colors and only the components you use. ## Dark mode and accessibility Every twblazor component ships with `dark:` variants, so dark mode works as soon as your app toggles the `dark` class on the root element. Components also include ARIA attributes and keyboard support, which you would otherwise have to build and test yourself. Browse the [button](https://twblazor.com/button.md), [textfield](https://twblazor.com/textfield.md), [data table](https://twblazor.com/data-table.md) and [color picker](https://twblazor.com/color-picker.md) pages to see live examples and the theme properties each one exposes. ## Next steps - Follow the [Get started](https://twblazor.com/get-started.md) guide to install twblazor in a Blazor Server or WebAssembly app. - Create your own palette with the [Theme builder](https://twblazor.com/theme). - Read the [Why twblazor?](https://twblazor.com/why-twblazor.md) page to see what sets it apart. --- # TwTextfield > TwTextfield is a Blazor text input component. Bind Value, use Multiline for a textarea, add a clear button with Clearable, and validate with Validator. Documentation page: https://twblazor.com/textfield ## Textfield Bind `Value` to a labeled text input with a placeholder. ```razor
``` ## Disabled textfield Use the `Disabled` property to prevent interaction with the textfield. ```razor ``` ## Readonly textfield Use the `ReadOnly` property to display a value that can't be edited. ```razor ``` ## Outlined variant Set `Variant="InputVariant.Outlined"` for an outlined textfield style. ```razor
``` ## Filled variant Set `Variant="InputVariant.Filled"` for a filled textfield style. ```razor
``` ## Different input types Use `InputType` to render native input types such as `email` and `password`. ```razor
``` ## Invalid textfield Set `Invalid` and `ErrorMessage` to mark the textfield as failing validation. The message is rendered below the input and associated with it via `aria-describedby` so assistive technology announces it alongside the field. ```razor ``` ## Dense textfield Set `Dense` for a more compact input with a smaller height and text size. Every single-line input shares the same dense height, so they line up when used side by side. ```razor ``` ## Clearable textfield Set `Clearable` to show an X button at the end of the field. It is disabled while the field is empty. Pressing it empties the field, runs `Validator`, invokes `OnClear` and moves focus back into the field. The button is not a Tab stop, since keyboard users can clear the text themselves, and it is hidden while the field is disabled or read-only. ```razor

Cleared @clearCount times.

``` ```csharp public string SearchTerm { get; set; } = "Order 1042"; public string Reference { get; set; } = "REF-7781"; private int clearCount; ``` ## Start and end content Use `StartContent` and `EndContent` to draw content over the start or end of a single-line field, such as an icon or a unit. The field's padding is not widened for it, so add padding through `Class` so the text does not run underneath. Hide decorative content from screen readers with `aria-hidden="true"`. ```razor ``` ## Validation on change Pass a `Validator` function to have the textfield validate itself whenever its value changes. Return `null` (or an empty string) when the value is valid, or an error message to automatically mark the field `Invalid` and display the returned message - no need to manage `Invalid` or `ErrorMessage` yourself. ```razor ``` ```csharp public string Username { get; set; } = string.Empty; private static Task ValidateUsername(string value) { if (string.IsNullOrWhiteSpace(value)) { return Task.FromResult("Username is required."); } if (value.Length < 3) { return Task.FromResult("Username must be at least 3 characters."); } return Task.FromResult(null); } ``` ## Asynchronous validation `Validator` returns a `Task`, so it can perform asynchronous work such as an API call without blocking the UI. This example simulates checking username availability against a server. ```razor ``` ```csharp public string NewUsername { get; set; } = string.Empty; private readonly HashSet _takenUsernames = new(StringComparer.OrdinalIgnoreCase) { "admin", "root", "jack" }; private async Task ValidateUsernameAvailabilityAsync(string value) { if (string.IsNullOrWhiteSpace(value)) { return "Username is required."; } // Simulate a network call to check availability against a server. await Task.Delay(300); return _takenUsernames.Contains(value) ? $"'{value}' is already taken." : null; } ``` ## Multiline textfield Set `Multiline` to render a `