Skip to content

AI

AiGenerativeUiView

Bit.BlazorUI.AI

BitAiGenerativeUiView renders a component the model chose, with the properties it produced. The model names a component and the view looks the name up in the generative UI registry - never a type name in the payload - so a model can only ever instantiate a component the app deliberately registered, and only set the parameters listed on it. Properties that are still streaming bind as far as they have arrived, so a card fills in as the model writes it; a name nothing is registered under renders a quiet placeholder, and the component runs inside an error boundary, so neither takes the answer around it down.

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.

BitAiGenerativeUiView resolves components through the IBitAiGenerativeUiRegistry that AddBitBlazorUIAIServices registers; the app fills it at startup with ConfigureGenerativeUi (see The registry). This site registers one component, forecast_card, which every live demo below renders. Inside a BitAiChat the view is rendered for every generative UI part on its own - see the Generative UI scenario.

Security: the registration is the boundary. Register only components that are safe to show with any values of their parameters, since a model - or whoever can steer its input - picks both. Callbacks, render fragments, the attributes catch-all and any type reaching a delegate or a Type are never bindable, whatever is registered.

Trimming: registering reads the parameter types by reflection, so Register is marked [RequiresUnreferencedCode] and [RequiresDynamicCode]. The component type itself is kept by the annotation of Register; an app that trims keeps the types its parameters reach (a plain string or number needs nothing), and says so with an [UnconditionalSuppressMessage] on the method that registers.

Usage

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

Basic

Give it a Part, a BitAiGenerativeUiPart naming a registered component and carrying its properties as JSON. The view finds forecast_card in the registry and renders the app's ForecastCard component with the parameters bound from the JSON - here as a session would leave it, finished.

Oslo
-3°
Snow81% humidity

Streaming properties

The properties of a part can stream in as raw JSON (AppendProps, what a BitAiGenerativeUiDeltaEvent does). The view re-binds them on every change, as far as they have arrived - a string even while it is being written - so the card fills in field by field rather than appearing at the end.



From a transport

A transport asks for a component with a BitAiGenerativeUiEvent - a name and the properties - and the session adds a generative UI part to the answer for each one. The scripted transport here asks for three forecast cards between two lines of text.



The registry

BitAiGenerativeUiRegistry.Register<TComponent>(name, description, required), through ConfigureGenerativeUi of AddBitBlazorUIAIServices, lets model output render a component under a name. Its bindable properties are its public [Parameter]s, less the ones no model should set: callbacks, render fragments, the attributes catch-all, any type whose graph reaches a delegate or a Type, and any parameter marked [BitAiGenerativeIgnore] (for one the app sets itself, such as a service key). [Description] on a parameter is what the model is told it means; on the component it is the description when Register is given none; a name in required - or a [Required] parameter - must be supplied.

DescribeAll writes all of it as one JSON Schema to hand the model (in a system prompt, or as the schema of a render tool) - without it the model guesses names, and every guess renders a placeholder. This is the schema this site's registry describes:

"type": "object""description": "Shows the current weather for one city.""const": "forecast_card"}"type": "object""type": "string""description": "The city name."}"type": "integer""description": "Temperature in degrees Celsius."}"type": "string""description": "One word summary, for example Clear, Snow, Showers."}"type": "integer""description": "Relative humidity as a percentage."}}"additionalProperties": false"description": "Shows the current weather for one city.""City"]}}"component""props"]}]}

Unregistered components

A name nothing is registered under never reaches a component: the view renders a warning tag named after it, once the part has finished - while it still streams, the name may be one the model is not done spelling - so a component a model made up costs the answer nothing.

No component named 'stock_ticker' is registered.

Binding diagnostics

A value of the wrong shape is skipped rather than thrown, and a property the component does not declare is ignored rather than passed - the card renders with what did bind. ShowBindingErrors lists both under the component once the part is complete: the errors - here an Unreadable value (degrees is no number; hover its tag for what the serializer said) and a Missing one (City, which the registration requires) - and the ignored names (wind), kept apart since only the first mean the card is missing something. Their texts are the strings of the options in force (see the tables below). Useful while writing the prompt, noise in production; the next example reads the same outcome in code.

0°
Windy
'degrees' could not be read as Int32'City' is required by 'forecast_card'Ignored: wind

Binding in code

The view binds through BitAiGenerativePropsBinder.Bind(component, props), which an app can call itself - to log what a model got wrong, or to check a payload before it is shown. It returns a BitAiGenerativeBindResult: the Parameters that bound, keyed by the name the component declares; the Failures, each a BitAiGenerativeBindError whose Kind is Unreadable (a value that cannot be read as the declared type, with that ExpectedType and what the serializer said, its Detail) or Missing (a required property left out), written in English in Errors for a log; the IgnoredProperties, names the component does not offer; and IsComplete, true when nothing failed.

The TicketCard here is a component of this page, registered in a registry of its own rather than the app's. Its schema (BitAiGenerativeComponent.Schema, below) shows what a registration leaves out: TenantId is marked [BitAiGenerativeIgnore] and OnBuy is a callback, so neither is offered to the model, and the payload's values for them are ignored like the made-up color.

"type": "object"}"additionalProperties": false"description": "Shows a ticket for an event.""Event"]}

IsComplete: False
  • Bound: Row = B
  • Unreadable: seats - 'seats' could not be read as Int32: The JSON value could not be converted to System.Int32. Path: $ | LineNumber: 0 | BytePositionInLine: 5.
  • Missing: Event - 'Event' is required by 'ticket_card'.
  • Ignored: tenantId
  • Ignored: onBuy
  • Ignored: color

Cascading parameters

BitParams with a BitAiGenerativeUiViewParams sets the defaults of every view inside it - one place to turn ShowBindingErrors on for a whole conversation while a prompt is being developed. A view's own value still wins.

0°
Windy
'degrees' could not be read as Int32'City' is required by 'forecast_card'Ignored: wind
0°
Windy

Style & Class

Style and Class reach the root, Styles and Classes each part: the container of the component, the placeholder tag, the diagnostics and their tags. The component itself is the app's, styled as the app styles it. The public --bit-AiGenerativeUiView-* variables (see the CSS variables table) inherit, so set on :root, a container or a view's Style they re-skin every view below.

Oslo
-3°
Snow81% humidity

0°
Windy
'degrees' could not be read as Int32'City' is required by 'forecast_card'Ignored: wind

0°
Windy
'degrees' could not be read as Int32'City' is required by 'forecast_card'Ignored: wind

RTL

In right-to-left text the container, the placeholder and the diagnostics start on the right, whether the direction comes from Dir or from a dir attribute around the view; the component inherits the direction like any markup inside it.

تهران
24°
آفتابی30% humidity

No component named 'stock_ticker' is registered.

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.

BitAiGenerativeUiView CSS variables

Name Default value Description
--bit-AiGenerativeUiView-diagnostics-gap spacing(1) Room between two tags of the binding diagnostics.
--bit-AiGenerativeUiView-diagnostics-margin spacing(1) Room between the component and its diagnostics.

API

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

BitAiGenerativeUiView parameters

Name Type Default value Description
Classes BitAiGenerativeUiViewClassStyles? null Custom CSS classes for different parts of the generative UI view.
Part BitAiGenerativeUiPart null The generative UI part to render (required): the name of the component the model chose and the JSON of its properties. The name is resolved through the IBitAiGenerativeUiRegistry, never as a type name, and the properties are bound onto the parameters that registration lists, again whenever the part changes - so a card streaming in fills in as far as its properties have arrived. A name nothing is registered under renders a warning tag once the part has finished streaming.
ShowBindingErrors bool false Lists, under the component, the properties that failed to bind (a value of the wrong shape, a required one missing) and the ones ignored because the component does not declare them, once the part has finished streaming. Useful while developing the prompt that produces them, noise in production; a BitAiGenerativeUiViewParams of a BitParams turns it on for a whole region.
Styles BitAiGenerativeUiViewClassStyles? null Custom CSS styles for different parts of the generative UI 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.

BitAiGenerativeUiViewClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the BitAiGenerativeUiView.
Content string? null Custom CSS classes/styles for the container of the rendered component of the BitAiGenerativeUiView.
Unregistered BitTagClassStyles? null Custom CSS classes/styles for the BitTag a component name nothing is registered under is shown as by the BitAiGenerativeUiView.
Diagnostics string? null Custom CSS classes/styles for the container of the binding diagnostics of the BitAiGenerativeUiView.
Error BitTagClassStyles? null Custom CSS classes/styles for the BitTag of each property that failed to bind in the BitAiGenerativeUiView.
Ignored BitTagClassStyles? null Custom CSS classes/styles for the BitTag of each property the component of the BitAiGenerativeUiView does not declare.

BitAiGenerativeUiPart properties

A part of a message naming a component the model chose, with the properties it produced as JSON. A session creates one for each BitAiGenerativeUiEvent of its transport and fills it from its BitAiGenerativeUiDeltaEvents; an app creates one to show a component outside a conversation. Safe to read on the renderer's thread while it is appended to on the transport's.

Name Type Default value Description
new(componentName, partId?) constructor Creates a streaming part for the component registered under that name.
ComponentName string The registered component name, as the model wrote it (matched case-insensitively).
Props JsonElement? null The properties once complete; until then a lenient parse of the JSON received so far, null while nothing parseable has arrived.
RawProps string "" The raw JSON property text received so far.
IsStreaming bool true Whether more properties may still arrive; the view says nothing of an unregistered name or of the binding until it is false.
AppendProps(delta) void Appends raw JSON property text.
SetProps(props) void Sets the complete properties at once.
Complete() void Marks the properties complete, parsing the accumulated text strictly when SetProps did not set them.

BitAiGenerativeUiRegistry properties

The components model output may render, registered as a singleton by AddBitBlazorUIAIServices (as IBitAiGenerativeUiRegistry too) and filled at startup through ConfigureGenerativeUi. Safe to read from any thread. The Register overloads read the parameter types by reflection, down to every type they reach, so they are marked [RequiresUnreferencedCode] and [RequiresDynamicCode]: an app that trims keeps those types itself and suppresses the warnings on the method that registers, with its reason.

Name Type Default value Description
Register<TComponent>(name, description?, params required) BitAiGenerativeComponent Registers a component under a name the model uses (keep it descriptive: the model reads it), replacing one registered under the same name. Its bindable properties are its public [Parameter] properties with a public setter, less callbacks, render fragments, CaptureUnmatchedValues, anything marked [BitAiGenerativeIgnore] and any type whose graph reaches a delegate, a Type or a component. [Description] on a parameter describes it to the model, and on the component is the description when none is given; a name in required, or a [Required] parameter, must be supplied.
Register(componentType, name, description?, params required) BitAiGenerativeComponent The same with the component type given as a Type; throws an ArgumentException for a type that is not a Blazor component.
Unregister(name) bool Removes a registration; true when one was removed.
Find(name) BitAiGenerativeComponent? The registration of a name, matched case-insensitively, or null - the case of a model naming something it should not have, which renders a placeholder.
Components IReadOnlyCollection<BitAiGenerativeComponent> [] Every registration.
DescribeAll() JsonElement A JSON Schema of every registration - a oneOf of { component, props } objects - for a system prompt or as the schema of a render tool. Handing it to the model is what makes generative UI reliable: without it the model guesses names.
IsBindable(type) bool (static) Whether a type is plain data a model may supply: false for delegates, render fragments, event callbacks, Type and any graph containing one.

BitAiGenerativeComponent properties

One registration: the component a name renders and the properties model output may set on it. It is the security boundary - a model can only name what is registered and set what is listed - and the prompting surface, through its Schema.

Name Type Default value Description
Name string The name the model uses.
ComponentType Type The Blazor component type it renders.
Description string? null What the component is for, included in the schema.
Properties IReadOnlyList<BitAiGenerativeProperty> [] The properties the model may set: each one's Name (as the model must spell it, matched case-insensitively), Type, Description and IsRequired.
Schema JsonElement The JSON Schema of its properties: nested objects with their own properties, collections with items, enums as their names, dates, identifiers and addresses as formatted strings, and additionalProperties false.
FindProperty(name) BitAiGenerativeProperty? A property by name, matched case-insensitively, as models are inconsistent.

BitAiGenerativeIgnoreAttribute properties

Keeps a parameter out of the set a model may set and out of the schema the model is shown - for a value the app sets itself, such as a service key or an identifier, which is not dangerous but which a model has no business choosing: [Parameter, BitAiGenerativeIgnore] public string TenantId { get; set; }.

Name Type Default value Description
[BitAiGenerativeIgnore] Property | Field Goes on a component parameter, or on a property or field of a parameter's type (a member of a record the component takes), once per member; inherited by overrides. The registry and the schema skip the member, and the binder ignores a value the model sends for it.

BitAiGenerativeProperty properties

One bindable property of a registration (a sealed record), as Register discovers it: new BitAiGenerativeProperty(name, type, description?, isRequired?).

Name Type Default value Description
Name string The parameter name, as the model must spell it (matched case-insensitively).
Type Type The CLR type the JSON value is read as.
Description string? null What the property means, from its [Description]; included in the schema the model is shown.
IsRequired bool false Whether the model must supply it: named in the required of Register, or marked [Required]. A required property left out is a Missing failure.

IBitAiGenerativeUiRegistry properties

What BitAiGenerativeUiView resolves names through - injected, so the registry is app-wide; AddBitBlazorUIAIServices registers BitAiGenerativeUiRegistry as it.

Name Type Default value Description
Components IReadOnlyCollection<BitAiGenerativeComponent> Every registered component.
Find(name) BitAiGenerativeComponent? The registration of a name, or null - which must render a fallback, since it is the case of a model naming something it should not have.

BitAiGenerativePropsBinder properties

Turns model-produced JSON into the parameters of a registered component - strict about what it accepts, forgiving about the rest: a name the registration does not offer is ignored rather than passed, and a value of the wrong shape is reported and skipped rather than thrown, so one bad field does not lose the whole card. It tolerates partial input, since props stream in and the component renders several times before they are done. BitAiGenerativeUiView calls it whenever its part changes; an app calls it to log or check a payload itself.

Name Type Default value Description
Bind(component, props) BitAiGenerativeBindResult (static) Binds a JSON object onto the properties of a registration, matching names case-insensitively. A null is bound only to a property that can hold it; anything but an object binds nothing and leaves every required property reported as missing.

BitAiGenerativeBindResult properties

The outcome of a binding (a sealed record). Failures are not fatal: the component renders with whatever did bind, because a partly usable card beats an error message.

Name Type Default value Description
Parameters IReadOnlyDictionary<string, object?> The parameters to render the component with, keyed by the name the component declares.
Failures IReadOnlyList<BitAiGenerativeBindError> [] The properties that did not bind, each with why - what a page shows, worded in its own language.
Errors IReadOnlyList<string> The same failures in English (each one's ToString()), in the same order, for a log.
IgnoredProperties IReadOnlyList<string> [] Names in the payload the component does not offer - not a parameter, not bindable, or marked [BitAiGenerativeIgnore] - as the model wrote them. Not errors: models routinely add one, and a model that keeps guessing names is a sign the schema it was given is out of date.
IsComplete bool True when every property supplied bound and every required one was there; ignored names do not count against it.

BitAiGenerativeBindError properties

A property that did not bind, and why (a sealed record): new BitAiGenerativeBindError(kind, propertyName). It describes the failure rather than wording it, so whoever shows it words it in the language of the page - BitAiGenerativeUiView through the UnreadableProperty and MissingProperty strings.

Name Type Default value Description
Kind BitAiGenerativeBindErrorKind Why the property did not bind.
PropertyName string The property: as the model wrote it for an Unreadable value, as the component declares it for a Missing one.
ComponentName string? null The name of the registration the property belongs to.
ExpectedType Type? null The type an Unreadable value was to be read as.
Detail string? null What the serializer said about an Unreadable value - written for a developer, in the language of the runtime; the view shows it as the tooltip of the error's tag.
ToString() string The English description a log reads, the same text Errors lists.

BitAiStrings (generative UI) properties

The texts of the view, members of the BitAiStrings of the options in force. Every member is virtual: a subclass overrides the ones it words differently and is handed as the Strings of the BitAiUiOptions - of a BitAiOptionsProvider, or of ConfigureUi (see /components/ai/optionsprovider#strings).

Name Type Default value Description
ComponentNotRegistered(component) string "No component named '{component}' is registered." The tooltip and accessible name of the warning tag of an unregistered name.
ComponentFailed(component) string "'{component}' could not be rendered" The notice of the error boundary when the component throws.
UnreadableProperty(name, type) string "'{name}' could not be read as {type}" The text of the tag of an Unreadable failure (the type as a person reads it: Int32, List).
MissingProperty(name, component) string "'{name}' is required by '{component}'" The text of the tag of a Missing failure.
IgnoredProperty(name) string "Ignored: {name}" The text of the tag of an ignored name.
IgnoredPropertyHint string "The component does not declare this property, so it was not passed." The tooltip of the tag of an ignored name.

BitAiGenerativeBindErrorKind enum

Name Value Description
Unreadable 0 The value the model wrote could not be read as the type the component declares for it ("very cold" for an int); the property is skipped and the rest still bind.
Missing 1 A property the component requires was not supplied (or was null where its type cannot hold one); the component still renders, without it.

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.