Skip to content

AI

AiArtifactView

Bit.BlazorUI.AICanvas

BitAiArtifactView is the panel an artifact lives in: the substantial piece of content an assistant produces beside its answer - a program, a document, a page, a table, an image - and revises over the turns that follow. The header holds the title, a version selector once there is more than one version, copy, download and a full-screen toggle; the body is chosen by the kind of the artifact - a renderer the app registered, or a built-in one: highlighted code, a streaming Markdown document, an HTML page in a sandboxed frame, a JSON tree, a table, or an image. The panel follows the artifact as it streams, and copy and download act on the version on screen.

Notes

To use this component, you need to install the Bit.BlazorUI.AI(opens in a new tab) nuget package, as described in the Optional steps of the Getting started page.

BitAiArtifactView reads the artifact renderers registered with AddBitBlazorUIAIServices (ConfigureRenderers), so the app calls it at startup even where it registers none, and downloads through the scripts of Bit.BlazorUI.AI. An artifact belongs to a conversation: a session creates it from the BitAiArtifactCreatedEvent, BitAiArtifactDeltaEvent and BitAiArtifactCompletedEvent of its transport and the message that introduced it shows it through BitAiArtifactPartView - see the Artifacts scenario for the whole chat.

Security: an HTML artifact is generated markup, so it is previewed in an iframe with sandbox="allow-scripts allow-forms allow-popups" - its scripts run, but it is denied same-origin access to the page, its storage and its cookies - and only once it has finished streaming. The frame is handed the page with one small script of the panel's own after it, which only posts the panel an Escape the page left alone; copy and download act on the page as it was written. An SVG is shown through an img, which never runs a script inside it. An image or an SVG follows the image policy of the options (BitAiUiOptions.Images, a BitAiImagePolicy), as the images of a message do: one the policy loads only on request is a button that loads it, one it blocks is replaced by the title of the artifact, and a source of a scheme that can run script is never loaded.

Accessibility: the panel is a section named after the artifact, its body says aria-busy while it streams, and the full-screen toggle says aria-pressed. The full-screen panel is a modal dialog (role="dialog", aria-modal) that holds the keyboard: Tab and Shift+Tab cycle through its controls and the page in its frame, and the Tab out of the end of that page comes back to the panel's first control rather than the page behind the overlay. Escape collapses it - pressed in the page in its frame too - claimed, so a dialog the panel sits in does not close on the same press. The button standing in for an image the image policy holds back hands the focus on to the image it loads.

Its texts - Download, Expand, Collapse, the Version label and its "Version N" items, "Load image: ..." and the notice of a renderer that failed - come from the strings in force (BitAiStrings), which a BitAiOptionsProvider localizes; the copy button is a BitAiCopyButton.

Usage

Every example is live. Open its code to see exactly what produced the component running underneath.

Basic

Give it an Artifact. A BitAiArtifact of the Code kind is shown as highlighted code in the language its Language names, under a header with its title, copy, download and the full-screen toggle.

Retry.cs
public static async Task<T> RetryAsync<T>(Func<Task<T>> action, int attempts = 3)
{
    for (var attempt = 1; ; attempt++)
    {
        try
        {
            return await action();
        }
        catch (HttpRequestException) when (attempt < attempts)
        {
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
        }
    }
}

Documents

A Document is prose written in Markdown, rendered as it streams - headings, lists, tables and code - and downloaded as a .md file.

Release notes

Release notes

What is new

  • Artifacts keep a version history across turns.

  • Structured output fills in while the JSON is still streaming.

AreaChange
ChatFaster streaming
FormsJSON Schema support
bash
dotnet add package Bit.BlazorUI.AI

HTML pages

An Html artifact is a self-contained page, previewed in a sandboxed frame once it is complete (while it streams it is shown as its code). The page below runs its own script - click its button - but cannot reach the page it sits in. The frame keeps a white background in a dark theme, the page a generated document expects.

Counter page

JSON & tables

A Json artifact is shown as a collapsible tree. A Table written as CSV - or TSV, when its Language is tsv - is shown as a table whose first row is the header, quoted fields and all; one written as a JSON array of objects becomes a BitAiDataTable. Each downloads in its own format.

Settings
"theme": "dark""fontSize": 14"autosave": true"README.md""Program.cs"]"proxy": null}

Prices
productpricestock
Keyboard, wireless89.5012
Mouse20140
Monitor 27"3294

Regions
regionsalesgrowth
Europe1.2M8%
Americas2.4M5%
Asia1.9M12%

Team
NameRoleRemote
AdaEngineertrue
GraceArchitectfalse

Images

An Image is shown from its Url (or a data URL as its content), named by its title; shown from an address it has no text to copy or download, so those two buttons are off. An Svg written as markup is shown as an image too, so a script inside it never runs (the badge below carries one), and downloads as an .svg file. Both follow the image policy of the options in force (BitAiUiOptions.Images, set here for a panel through a BitAiOptionsProvider), as the images of a message do: under ClickToLoad (the third panel) the body is a button, named after the artifact, that loads the image - press it - and under Block (the last) it is the title alone, even for an SVG that is fetched from nowhere.

Mountain lake
Mountain lake

Badge
Badge

Mountain lake

Badge
Badge

Other kinds

BitAiArtifactKind is a string-backed value rather than an enum, so a transport may send kinds the package does not know. A Chart, a Diagram or a kind of the app's own (new BitAiArtifactKind("mermaid")) has no built-in rendering and is shown as its code - highlighted in its Language when it names one - until the app registers a renderer for it (next example). The glyph beside the title follows the kind too.

Monthly sales
{ "type": "bar", "labels": ["Jan", "Feb", "Mar"], "data": [120, 180, 150] }

Sign-in flow
flowchart LR
    User --> Login --> Check{Valid?}
    Check -- yes --> Home
    Check -- no --> Login

Custom renderers

A renderer registered for a kind (BitAiRendererRegistry.RegisterArtifact, see the tables below) draws the body of every panel of that kind - a built-in kind or one of the app's own - in place of the built-in body, under the same header with its copy, download and full screen. It is a BitAiArtifactRenderer, handed a BitAiArtifactContext: the Artifact; the Version on screen and its Content, which follow the version selector (draw the context's Content, never the artifact's, which is always the latest version's); and IsExpanded, whether the panel is full screen - expand the first panel and the chart grows. It runs inside a BitAiRendererBoundary, so a renderer that throws on a spec it did not expect - the second chart has no data - is replaced by a notice rather than taking the page down. An app registers its renderers once, at startup (ConfigureRenderers of AddBitBlazorUIAIServices); that registry is app-wide, so this example cascades a registry of its own (a CascadingValue of a BitAiRendererRegistry), which the panels inside it use in place of the registered one. The whole registry is described on the AiMessagePartView page.

Monthly sales
Jan
Feb
Mar

Quarterly sales
The renderer for 'chart' failed

Streaming

The panel follows the artifact as it streams - re-rendering at most once per render interval of the AI options, with loading dots in its header and its body marked busy. The scripted transport here writes a README into an artifact on the first turn and revises the same artifact on the next one, so the second press adds version 2 and the version selector appears.



Versions

BeginRevision starts a new version and keeps the last one in Versions, a history of BitAiArtifactVersions with an optional summary of what changed; Complete commits it. The selector lists every version, and the panel keeps showing the one picked while newer ones arrive. InitialVersion opens a panel at an older version - the one a particular turn produced - and Restore brings an old version back as a new one.



pricing.ts
export const price = (quantity: number) => quantity * (quantity >= 10 ? 9 : 10);

pricing.ts
export const price = 10;

  • Version 1: First draft
  • Version 2: Priced per unit
  • Version 3: A bulk discount

Copy, download & full screen

Copy and download act on the version on screen. The file is named after the title, with -v1 and so on for an older version, and takes the extension and type of its kind and language: .md, .html, .json, .csv, .tsv, .svg, or one of some twenty languages (.cs, .ts, .py, ...) for code. The full-screen toggle lays the same panel over the page - a running page in its frame is never restarted by it - and Escape or a click on the overlay brings it back. A Disabled panel turns its copy and download buttons, the version selector and the full-screen toggle off; its content stays readable.

Counter page

pricing.ts
export const price = (quantity: number) => quantity * (quantity >= 10 ? 9 : 10);

Cascading parameters

BitParams with a BitAiArtifactViewParams sets the Classes and Styles of the parts - and the parameters every component shares, such as Disabled or Dir - of every artifact panel inside it, rather than the artifact and the version a single panel shows. A panel keeps what it sets itself: the second one gives Styles of its own, so the cascaded ones do not reach it.

Retry.cs
public static async Task<T> RetryAsync<T>(Func<Task<T>> action, int attempts = 3)
{
    for (var attempt = 1; ; attempt++)
    {
        try
        {
            return await action();
        }
        catch (HttpRequestException) when (attempt < attempts)
        {
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
        }
    }
}

Settings
"theme": "dark""fontSize": 14"autosave": true"README.md""Program.cs"]"proxy": null}

Style & Class

Style and Class reach the root, Styles and Classes each part (the version selector, the copy button, the other buttons and the loading dots take the class-styles of BitDropdown, BitAiCopyButton, BitButton and BitLoading). The public --bit-AiArtifactView-* variables (see the CSS variables table) inherit, so set on :root, a container or a panel's Style they re-skin every panel below - a panel a registered renderer nests inside it too. The buttons color themselves through the --bit-Button-* variables rather than the color of the header, so a header given a color of its own sets them as well.

Retry.cs
public static async Task<T> RetryAsync<T>(Func<Task<T>> action, int attempts = 3)
{
    for (var attempt = 1; ; attempt++)
    {
        try
        {
            return await action();
        }
        catch (HttpRequestException) when (attempt < attempts)
        {
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
        }
    }
}

Release notes

Release notes

What is new

  • Artifacts keep a version history across turns.

  • Structured output fills in while the JSON is still streaming.

AreaChange
ChatFaster streaming
FormsJSON Schema support
bash
dotnet add package Bit.BlazorUI.AI

Release notes

Release notes

What is new

  • Artifacts keep a version history across turns.

  • Structured output fills in while the JSON is still streaming.

AreaChange
ChatFaster streaming
FormsJSON Schema support
bash
dotnet add package Bit.BlazorUI.AI

RTL

In right-to-left text the header and the body read from the right, whether the direction comes from Dir or from a dir attribute around the panel.

یادداشت انتشار

یادداشت انتشار

  • آرتیفکت‌ها تاریخچه نسخه‌ها را نگه می‌دارند.

  • خروجی ساختاریافته همزمان با رسیدن JSON پر می‌شود.


یادداشت انتشار

یادداشت انتشار

  • آرتیفکت‌ها تاریخچه نسخه‌ها را نگه می‌دارند.

  • خروجی ساختاریافته همزمان با رسیدن JSON پر می‌شود.

CSS variables

The public custom properties this component reads off its root, for what no parameter covers.

Every variable is read with a fallback and never declared by the component, so it inherits like any other custom property: set one on :root (or in a [bit-theme] block) to restyle every instance, on any ancestor to restyle the ones inside it, or on the Style of one instance to restyle it - and any instance nested inside it, which inherits the value too; a parameter changes one alone, as does the real CSS property on the instance's Style / Styles when that property does not inherit (opacity: 1 keeps one disabled instance undimmed without undimming a disabled one inside it), while an inherited one such as color or font-family also reaches the nested instances that do not set it themselves. Leave a variable unset and the component falls back to the theme token beside it.

BitAiArtifactView CSS variables

Name Default value Description
--bit-AiArtifactView-background var(--bit-clr-bg-pri) Background of the panel.
--bit-AiArtifactView-color var(--bit-clr-fg-pri) Color of the text of the panel.
--bit-AiArtifactView-border-color var(--bit-clr-brd-pri) Color of the frame of the panel.
--bit-AiArtifactView-radius var(--bit-shp-radius-surface) Corner of the panel.
--bit-AiArtifactView-header-background var(--bit-clr-bg-sec) Background of the header.
--bit-AiArtifactView-header-padding spacing(1) spacing(1.5) Inset of the header.
--bit-AiArtifactView-header-gap spacing(1) Room between the parts of the header.
--bit-AiArtifactView-divider-color var(--bit-clr-brd-sec) Color of the rule under the header.
--bit-AiArtifactView-icon-color var(--bit-clr-fg-sec) Color of the icon of the kind beside the title.
--bit-AiArtifactView-title-font-size var(--bit-tpg-fs-sm) Size of the title.
--bit-AiArtifactView-title-font-weight var(--bit-tpg-fw-semibold) Weight of the title.
--bit-AiArtifactView-max-height spacing(64) Height past which the body of an inline panel scrolls; the full-screen panel fills the screen instead.
--bit-AiArtifactView-content-padding spacing(1.5) spacing(2) Inset of a document or a JSON tree in the body, and of what stands in for an image or an SVG artifact the image policy holds back (its placeholder button or its title).
--bit-AiArtifactView-muted-color var(--bit-clr-fg-sec) Color of the title shown in place of an image or an SVG artifact the image policy blocks.
--bit-AiArtifactView-frame-height spacing(52) Height of the frame of an HTML page in an inline panel; the full-screen panel stretches it to the body.
--bit-AiArtifactView-frame-background white Background of the frame of an HTML page - the white page a generated document expects, kept in a dark theme too.
--bit-AiArtifactView-expanded-inset spacing(2); none on a small screen Room between the full-screen panel and the edges of the screen.
--bit-AiArtifactView-overlay-background var(--bit-clr-bg-overlay) Background of the overlay behind the full-screen panel.
--bit-AiArtifactView-table-divider-color var(--bit-clr-brd-sec) Color of the rules between the rows of a CSV or TSV table.
--bit-AiArtifactView-table-header-background var(--bit-clr-bg-sec) Background of the header row of a CSV or TSV table.

API

Every parameter, public member, sub-class and enum this component exposes.

BitAiArtifactView parameters

Name Type Default value Description
Artifact BitAiArtifact null The artifact to show (required). The panel follows it as it changes - a streaming artifact re-renders it at most once per render interval of the AI options - and picks its body by its Kind: the renderer the app registered for that kind, else the built-in one.
Classes BitAiArtifactViewClassStyles? null Custom CSS classes for different parts of the artifact view.
InitialVersion int? null The version to show until the user picks another, for example the one a particular turn produced, so a later revision does not rewrite what an earlier turn appears to have said. The latest version is shown while it is unset, or when the artifact has no such version. Handing the panel another artifact drops the user's pick.
Styles BitAiArtifactViewClassStyles? null Custom CSS styles for different parts of the artifact view.

BitComponentBase parameters

Name Type Default value Description
AriaLabel string? null Gets or sets the accessible label for the component, used by assistive technologies.
Class string? null Gets or sets the CSS class name(s) to apply to the rendered element.
Dir BitDir? null Gets or sets the text directionality for the component's content.
Disabled bool false Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction.
ForceAnimation bool false Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested.
HtmlAttributes Dictionary<string, object> new Dictionary<string, object>() Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. An attribute written on the component wins over an entry of the same name.
Id string? null Gets or sets the unique identifier for the component's root element.
Style string? null Gets or sets the CSS style string to apply to the rendered element.
TabIndex string? null Gets or sets the tab order index for the component when navigating with the keyboard.
Visibility BitVisibility BitVisibility.Visible Gets or sets the visibility state (visible, hidden, or collapsed) of the component.

BitComponentBase public members

Name Type Default value Description
UniqueId Guid Guid.NewGuid() Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed.
RootElement ElementReference Gets the reference to the root HTML element associated with this component.

BitAiArtifactViewClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the BitAiArtifactView.
Overlay string? null Custom CSS classes/styles for the overlay laid over the page behind the full-screen panel of the BitAiArtifactView.
Panel string? null Custom CSS classes/styles for the panel - the header and the body - of the BitAiArtifactView.
Header string? null Custom CSS classes/styles for the header of the BitAiArtifactView.
Icon string? null Custom CSS classes/styles for the icon of the kind of the artifact in the header of the BitAiArtifactView.
Title string? null Custom CSS classes/styles for the title of the BitAiArtifactView.
Loading BitLoadingClassStyles? null Custom CSS classes/styles for the BitEllipsisLoading the header of the BitAiArtifactView shows while the artifact streams.
VersionDropdown BitDropdownClassStyles? null Custom CSS classes/styles for the BitDropdown that picks the version shown by the BitAiArtifactView.
CopyButton BitAiCopyButtonClassStyles? null Custom CSS classes/styles for the copy button (a BitAiCopyButton) of the BitAiArtifactView.
DownloadButton BitButtonClassStyles? null Custom CSS classes/styles for the download BitButton of the BitAiArtifactView.
ExpandButton BitButtonClassStyles? null Custom CSS classes/styles for the full-screen toggle BitButton of the BitAiArtifactView.
Body string? null Custom CSS classes/styles for the body of the BitAiArtifactView.
Content string? null Custom CSS classes/styles for the container of a document or a JSON tree in the body of the BitAiArtifactView.
Image string? null Custom CSS classes/styles for the image an image or an SVG artifact is shown as by the BitAiArtifactView.
ImagePlaceholder BitActionButtonClassStyles? null Custom CSS classes/styles for the button (a BitActionButton) the BitAiArtifactView shows in place of an image or an SVG artifact the image policy loads only on request.
BlockedImage string? null Custom CSS classes/styles for the title the BitAiArtifactView shows in place of an image or an SVG artifact the image policy blocks.
Frame string? null Custom CSS classes/styles for the sandboxed frame an HTML artifact is previewed in by the BitAiArtifactView.
Table string? null Custom CSS classes/styles for the box of the table a CSV or TSV artifact is shown as by the BitAiArtifactView.
HeaderCell string? null Custom CSS classes/styles for each header cell of the table of a CSV or TSV artifact of the BitAiArtifactView.
Cell string? null Custom CSS classes/styles for each body cell of the table of a CSV or TSV artifact of the BitAiArtifactView.

BitAiArtifact properties

A substantial piece of content produced alongside a conversation and revised across turns. It belongs to the conversation rather than to a message (BitAiConversation.Artifacts, GetOrAddArtifact, FindArtifact), so a rewrite three turns later updates one object with a version history instead of scattering near-identical copies through the transcript. A session creates and fills it from the artifact events of its transport; an app creates one to show content of its own. Safe for one writer and concurrent readers.

Name Type Default value Description
new(artifactId, kind, title) constructor Creates a streaming artifact at version 1; a null artifactId generates one. Append or SetContent its content, then Complete it.
ArtifactId string The identifier, unique within a conversation.
Kind BitAiArtifactKind The kind of the artifact, which picks its renderer.
Title string The title in the header, which also names the downloaded file. Changed through SetTitle.
Content string? "" The content of the current version, as text.
Language string? null A language or format hint: the language code is highlighted in and downloaded as (csharp, typescript, python, ...), and tsv for a tab-separated table.
Url string? null An address for content that is not inline text, such as the source of an image.
Version int 1 The one-based number of the current version, incremented by every revision.
IsStreaming bool true Whether the current version is still being written: the panel shows its loading dots and previews an HTML page or an SVG only once it is false.
Versions IReadOnlyList<BitAiArtifactVersion> [] Every committed version, oldest first; the current draft is not included.
Metadata IReadOnlyDictionary<string, object?>? null Application-defined values carried through to a registered artifact renderer.
CreatedAt / UpdatedAt DateTimeOffset When the artifact was created, and when its current version last changed.
Length / ChangeVersion int 0 How many characters the content holds, without materializing it; and a counter bumped on every change, for cheap render checks.
Append(delta) void Appends content to the current version, in linear time however long the artifact grows.
SetContent(content) void Replaces the content of the current version.
SetTitle(title) void Renames the artifact.
Complete(summary?) void Commits the current content as a version, with an optional summary of what changed, and stops streaming. Completing it again records nothing new, but can add the summary the first call lacked.
BeginRevision() void Starts the next version, empty and streaming, completing the current one first if it is not; the previous version stays in Versions for the selector.
Restore(version) bool Brings the content of an earlier version back as a new version, summarized "Restored version N"; false when there is no such version.
Changed event Action<BitAiArtifact> Raised after every change, which is what the panel follows the artifact by.

BitAiArtifactVersion properties

An immutable snapshot of an artifact at one version, recorded by Complete - one entry of Versions and of the version selector.

Name Type Default value Description
Version int The one-based version number.
Content string? The content at this version, which the panel shows, copies and downloads when the version is picked.
CreatedAt DateTimeOffset When this version was committed.
Summary string? null An optional description of what changed, from Complete(summary) or the Summary of a BitAiArtifactCompletedEvent.

BitAiRendererRegistry properties

Where an app registers its own renderers, which the components resolve before their built-in views. A singleton: register at startup (AddBitBlazorUIAIServices(ai => ai.ConfigureRenderers(renderers => ...))) and treat the entries as fixed afterwards - every entry is app-wide. A region with renderers of its own cascades a registry of its own (new BitAiRendererRegistry(), in a CascadingValue), which every AI component inside it uses in place of the registered one. These are its artifact members; the whole registry is on the AiMessagePartView page (/components/ai/messagepartview#renderer-registry).

Name Type Default value Description
RegisterArtifact(kind, renderer) void Registers a BitAiArtifactRenderer for an artifact kind (case does not matter) - a built-in kind or one of the app's own. Every BitAiArtifactView of an artifact of that kind renders it as its body in place of the built-in one, inside a BitAiRendererBoundary; a later registration replaces an earlier one.
FindArtifact(kind) BitAiArtifactRenderer? The renderer registered for an artifact kind, or null when the built-in body draws it.

BitAiArtifactRenderer properties

The delegate a custom artifact renderer is: public delegate RenderFragment BitAiArtifactRenderer(BitAiArtifactContext context). It is called on every render of the panel - each coalesced change of a streaming artifact and each turn of the full-screen toggle - so it reads what it draws off the context as it is called. It draws the context's Content - the content of the version on screen, which follows the panel's version selector - rather than the artifact's own Content, which is always the latest one's.

Name Type Default value Description
context BitAiArtifactContext The artifact and how it is being shown.
(return value) RenderFragment The markup drawn as the body of the panel, under its header.

BitAiArtifactContext properties

What a renderer registered with BitAiRendererRegistry.RegisterArtifact(kind, context => ...) is handed (a sealed record). The renderer draws the body of every panel of that kind, inside a BitAiRendererBoundary.

Name Type Default value Description
Artifact BitAiArtifact The artifact being shown.
IsExpanded bool false Whether the panel is full screen, for a renderer that lays itself out to the room it has.
Version int Artifact.Version The version on screen: the latest one unless an earlier one was picked in the version selector of the panel (or set as its InitialVersion).
Content string? Artifact.Content The content of the version on screen - what a renderer draws. The artifact's own Content is always the latest version's, so a renderer reading it would ignore the version selector.
IsLatest bool Whether the version on screen is the latest one - the only one that can still be streaming (Artifact.IsStreaming).

BitAiArtifactKind enum

Name Value Description
Document "document" Prose in Markdown, rendered as streaming Markdown and downloaded as .md.
Code "code" Source code, highlighted in its Language and downloaded with that language's extension.
Html "html" A self-contained HTML page, previewed in a sandboxed frame once complete (shown as its code while it streams) and downloaded as .html.
Json "json" A JSON value, rendered as a collapsible tree and downloaded as .json.
Table "table" Tabular data: CSV (or TSV when the Language is tsv) as a table whose first row is the header, or a JSON array of objects as a BitAiDataTable; downloaded as .csv, .tsv or .json.
Chart "chart" A chart specification, for a renderer the app registers; shown as its code otherwise.
Image "image" A raster or vector image, shown from its Url or from a data URL as its content, as the image policy of the options decides.
Svg "svg" SVG markup, shown through an img once complete - so no script inside it runs - as the image policy of the options decides, and downloaded as .svg.
Diagram "diagram" A diagram description, for a renderer the app registers; shown as its code otherwise.

BitVisibility enum

Name Value Description
Visible 0 The content of the component is visible.
Hidden 1 The content of the component is hidden, but the space it takes on the page remains (visibility:hidden).
Collapsed 2 The component is hidden (display:none).

BitDir enum

Name Value Description
Ltr 0 Ltr (left to right) is to be used for languages that are written from the left to the right (like English).
Rtl 1 Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic).
Auto 2 Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.

Feedback

Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.