Skip to content
# AiAttachmentChip **Also known as:** FileChip ## Description BitAiAttachmentChip shows one BitAiAttachment as a chip - a BitTag: a thumbnail for an image and the glyph of its kind for anything else, its name, and under it its size, the progress of an upload still arriving, or why the upload failed. Its dismiss button removes the attachment, there only while OnRemove is set. The composer stages files as these chips, and a message shows its files with them. ## Parameters | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Attachment | `BitAiAttachment` | | The attachment to show: its Name, its Kind (the thumbnail or glyph before the name) and, under the name, its Size, its upload Progress or its Error, as its Status says. Required. | | Classes | `BitAiAttachmentChipClassStyles?` | null | Custom CSS classes for different parts of the attachment chip. | | OnRemove | `EventCallback<BitAiAttachment>` | | Raised with the attachment when the user removes it. The remove button - the dismiss button of the tag, named Remove and the file name - is there only while this is set. | | Styles | `BitAiAttachmentChipClassStyles?` | null | Custom CSS styles for different parts of the attachment chip. | | 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. | ## Public Members | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | FocusAsync | `ValueTask` | | Gives the keyboard focus to the remove button of the chip - what a row of chips hands the focus on with after removing one, since the button that was pressed goes with its chip. A chip without OnRemove has no button and nothing to focus. | | 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. | ## Enums ### BitAiAttachmentKind Enum | Name | Value | Description | | :--- | :--- | :---------- | | File | 0 | Anything without a more specific category. The chip shows the glyph of a page. | | Image | 1 | A raster or vector image. The chip shows its ThumbnailUrl, else its Url, where the image policy shows it outright, and the glyph of a picture otherwise. | | Audio | 2 | An audio clip. The chip shows the glyph of a microphone. | | Video | 3 | A video clip. The chip shows the glyph of a video camera. | | Document | 4 | A PDF or other paginated document. The chip shows the glyph of a page, as for any other file. | ### BitAiAttachmentStatus Enum | Name | Value | Description | | :--- | :--- | :---------- | | Pending | 0 | Selected locally and not yet uploaded. The chip shows the size, as it does once the file is ready. | | Uploading | 1 | Upload in progress. The chip shows the Progress as a percentage (0% while it is null). | | Ready | 2 | Available to the model. The chip shows the size, when it is known. | | Failed | 3 | The upload failed. The chip shows the Error (the UploadFailed text of the strings in force when it is null) in the error color. | ### 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. | ## Sub Classes ### BitAiAttachmentChipClassStyles Properties | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Root | `string?` | null | Custom CSS classes/styles for the root element of the BitAiAttachmentChip. | | Tag | `BitTagClassStyles?` | null | Custom CSS classes/styles for the BitTag of the BitAiAttachmentChip that carries the name, the details and the remove button. | | Thumbnail | `string?` | null | Custom CSS classes/styles for the thumbnail of the BitAiAttachmentChip: the picture of an image, or the box holding the glyph of any other kind of file. | | Icon | `string?` | null | Custom CSS classes/styles for the glyph of the BitAiAttachmentChip shown in place of a picture. | ### BitAiAttachment Properties A file carried by a message or staged in the composer: new BitAiAttachment(attachmentId, name) { ... }. It holds no byte array of its own, so Blazor Server never keeps a multi-megabyte upload in circuit memory: its content is referenced through Url, Data or ContentFactory and only read when something needs it. | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | AttachmentId | `string` | | An identifier unique within its message or composer, a good @key. Required; it cannot be empty. | | Name | `string` | | The file name shown to the user. | | ContentType | `string?` | null | The MIME type, for example image/png. | | Size | `long?` | null | The size in bytes, when known. The chip shows it, formatted (FormatBytes of the strings in force), once the file is ready. | | Kind | `BitAiAttachmentKind` | BitAiAttachmentKind.File | The category that decides the preview: a thumbnail for an image, the glyph of its kind otherwise. InferKind works it out of a MIME type and a file name. | | Status | `BitAiAttachmentStatus` | BitAiAttachmentStatus.Ready | Where the upload of the file is. | | Progress | `double?` | null | The progress of the upload, from 0 to 1, while the Status is Uploading. | | Error | `string?` | null | Why the upload failed, when the Status is Failed. When null, the UploadFailed text of the strings in force is shown. | | Url | `string?` | null | An addressable URL for the content, which may be a data URL for a small inline file. The chip shows it for an image without a ThumbnailUrl. | | ThumbnailUrl | `string?` | null | A URL for a small preview image, distinct from the full-size content, which the chip prefers for an image. | | Data | `ReadOnlyMemory<byte>?` | null | Inline bytes, for small attachments that are cheap to keep in memory. | | ContentFactory | `Func<CancellationToken, ValueTask<Stream>>?` | null | Opens the content on demand. Preferred over Data for anything large; never serialized. | | Metadata | `IReadOnlyDictionary<string, object?>?` | null | App-defined values carried through to custom attachment renderers. | | HasInlineData | `bool` | false | Whether the content can be read without a round trip (Data is set). | | OpenReadAsync(CancellationToken cancellationToken) | `ValueTask<Stream>` | | Opens the content from whichever source there is: the ContentFactory, else the Data. Throws an InvalidOperationException for an attachment carrying neither. | | InferKind(string? contentType, string? fileName) | `static BitAiAttachmentKind` | | Infers the kind from a MIME type (image/*, audio/*, video/*, application/pdf), or from the extension of the file name when the type is missing or generic. | ## CSS Variables Public CSS custom properties read off the component's root. Set one on `:root` to restyle every instance, on any ancestor to restyle the ones inside it, or on the `Style` of one instance to restyle it and every instance nested inside it, which inherits the value too - a parameter changes one alone, as does the real CSS property on its `Style` / `Styles` when that property does not inherit (`opacity`); an inherited one (`color`, `font-family`) reaches the nested instances that do not set it themselves. | Name | Default Value | Description | | :--- | :------------ | :---------- | | `--bit-AiAttachmentChip-max-width` | spacing(32) | Widest the chip gets before its name is cut short. | | `--bit-AiAttachmentChip-thumbnail-size` | spacing(4.25) | Width and height of the thumbnail of an image, and of the box holding the glyph of any other file. | | `--bit-AiAttachmentChip-thumbnail-radius` | var(--bit-shp-radius-sm) | Corner of the thumbnail. | | `--bit-AiAttachmentChip-thumbnail-background` | var(--bit-clr-bg-sec) | Fill behind the glyph, or behind a picture that does not cover its box. | | `--bit-AiAttachmentChip-thumbnail-color` | var(--bit-clr-fg-sec) | Color of the glyph shown in place of a picture. | ## Examples \n**Basic**: ```razor ``` ```csharp private readonly BitAiAttachment report = new("att-report", "quarterly-report.pdf") { ContentType = "application/pdf", Size = 482_133, Kind = BitAiAttachmentKind.Document, }; private readonly BitAiAttachment longName = new("att-long", "minutes-of-the-planning-meeting-with-the-whole-team.docx") { Size = 23_552, Kind = BitAiAttachmentKind.Document, }; ``` \n**Kinds**: ```razor
@foreach (var attachment in kinds) { }
``` ```csharp private const string PhotoUrl = "_content/Bit.BlazorUI.Demo.Client.Core/images/carousel/img1.jpg"; private readonly IReadOnlyList kinds = [ new("att-kind-image", "aurora.jpg") { Size = 1_843_200, Kind = BitAiAttachment.InferKind("image/jpeg"), ThumbnailUrl = PhotoUrl }, new("att-kind-audio", "voice-note.m4a") { Size = 412_000, Kind = BitAiAttachment.InferKind(null, "voice-note.m4a") }, new("att-kind-video", "screen-recording.webm") { Size = 9_830_400, Kind = BitAiAttachment.InferKind("video/webm") }, new("att-kind-document", "contract.pdf") { Size = 220_160, Kind = BitAiAttachment.InferKind("application/pdf") }, new("att-kind-file", "data.csv") { Size = 5_120, Kind = BitAiAttachment.InferKind("text/csv", "data.csv") }, ]; ``` \n**Image policy**: ```razor
``` ```csharp private const string PhotoUrl = "_content/Bit.BlazorUI.Demo.Client.Core/images/carousel/img1.jpg"; private readonly BitAiAttachment photo = new("att-photo", "aurora.jpg") { ContentType = "image/jpeg", Size = 1_843_200, Kind = BitAiAttachmentKind.Image, ThumbnailUrl = PhotoUrl, }; // An app sets the policy once, for every view (AddBitBlazorUIAIServices(ai => ai.ConfigureUi(...)) or a provider // around the whole chat); here a provider sets it for the second chip alone. private readonly BitAiUiOptions blockImagesOptions = BitAiUiOptions.Default with { Images = BitAiImagePolicy.Block }; ``` \n**Status**: ```razor Upload a file
``` ```csharp private bool isUploading; private BitAiAttachment upload = new("att-upload", "site-survey.zip") { Size = 3_145_728, Status = BitAiAttachmentStatus.Pending }; private readonly BitAiAttachment failed = new("att-failed", "backup.tar") { Size = 734_003_200, Status = BitAiAttachmentStatus.Failed, Error = "Over the 100 MB limit of the server", }; private async Task UploadAsync() { isUploading = true; for (var progress = 0.0; progress < 1.0; progress += 0.1) { upload = upload with { Status = BitAiAttachmentStatus.Uploading, Progress = progress }; StateHasChanged(); await Task.Delay(250); } upload = upload with { Status = BitAiAttachmentStatus.Ready, Progress = null }; isUploading = false; } ``` \n**OnRemove**: ```razor
@foreach (var attachment in staged) { }
Bring them back ``` ```csharp private const string PhotoUrl = "_content/Bit.BlazorUI.Demo.Client.Core/images/carousel/img1.jpg"; private List staged = CreateStaged(); private readonly Dictionary stagedChips = []; private BitButton resetButton = default!; private static List CreateStaged() => [ new("att-staged-1", "aurora.jpg") { Size = 1_843_200, Kind = BitAiAttachmentKind.Image, ThumbnailUrl = PhotoUrl }, new("att-staged-2", "notes.txt") { Size = 1_024 }, new("att-staged-3", "budget.xlsx") { Size = 48_640 }, ]; private async Task Remove(BitAiAttachment attachment) { var index = staged.IndexOf(attachment); staged.Remove(attachment); stagedChips.Remove(attachment.AttachmentId); // The remove button goes with its chip: the focus moves to the chip that took its place, or the last one, or the // button that brings them back once none is left. if (staged.Count > 0) { await stagedChips[staged[Math.Min(index, staged.Count - 1)].AttachmentId].FocusAsync(); } else { await resetButton.FocusAsync(); } } private void ResetStaged() { staged = CreateStaged(); } ``` \n**Disabled**: ```razor ``` ```csharp private readonly BitAiAttachment report = new("att-report", "quarterly-report.pdf") { ContentType = "application/pdf", Size = 482_133, Kind = BitAiAttachmentKind.Document, }; // Never called: the remove button of a disabled chip cannot be pressed. private void RemoveDisabled(BitAiAttachment attachment) { } ``` \n**Cascading parameters**: ```razor
``` ```csharp private const string PhotoUrl = "_content/Bit.BlazorUI.Demo.Client.Core/images/carousel/img1.jpg"; private readonly BitAiAttachmentChipParams[] attachmentChipParams = [ new() { Styles = new() { Tag = new() { Root = "border-radius:1rem" }, Thumbnail = "border-radius:50%" } } ]; private readonly BitAiAttachment report = new("att-report", "quarterly-report.pdf") { ContentType = "application/pdf", Size = 482_133, Kind = BitAiAttachmentKind.Document, }; private readonly BitAiAttachment photo = new("att-photo", "aurora.jpg") { ContentType = "image/jpeg", Size = 1_843_200, Kind = BitAiAttachmentKind.Image, ThumbnailUrl = PhotoUrl, }; private readonly BitAiAttachment longName = new("att-long", "minutes-of-the-planning-meeting-with-the-whole-team.docx") { Size = 23_552, Kind = BitAiAttachmentKind.Document, }; ``` \n**Style & Class**: ```razor
``` ```csharp private const string PhotoUrl = "_content/Bit.BlazorUI.Demo.Client.Core/images/carousel/img1.jpg"; private const string cssVariablesStyle = "--bit-AiAttachmentChip-max-width:12rem;" + "--bit-AiAttachmentChip-thumbnail-size:2.5rem;" + "--bit-AiAttachmentChip-thumbnail-radius:50%;" + "--bit-AiAttachmentChip-thumbnail-background:var(--bit-clr-pri);" + "--bit-AiAttachmentChip-thumbnail-color:var(--bit-clr-pri-text);" + "--bit-Tag-radius:2rem;"; private readonly BitAiAttachment report = new("att-report", "quarterly-report.pdf") { ContentType = "application/pdf", Size = 482_133, Kind = BitAiAttachmentKind.Document, }; private readonly BitAiAttachment longName = new("att-long", "minutes-of-the-planning-meeting-with-the-whole-team.docx") { Size = 23_552, Kind = BitAiAttachmentKind.Document, }; private readonly BitAiAttachment photo = new("att-photo", "aurora.jpg") { ContentType = "image/jpeg", Size = 1_843_200, Kind = BitAiAttachmentKind.Image, ThumbnailUrl = PhotoUrl, }; ``` \n**RTL**: ```razor
Removed: @rtlRemoved
``` ```csharp private const string PhotoUrl = "_content/Bit.BlazorUI.Demo.Client.Core/images/carousel/img1.jpg"; private readonly BitAiAttachment persianReport = new("att-fa-report", "گزارش-فصلی.pdf") { Size = 482_133, Kind = BitAiAttachmentKind.Document, }; private readonly BitAiAttachment persianPhoto = new("att-fa-photo", "شفق-قطبی.jpg") { Size = 1_843_200, Kind = BitAiAttachmentKind.Image, ThumbnailUrl = PhotoUrl, }; private string rtlRemoved = "nothing yet"; private void RemoveRtl(BitAiAttachment attachment) { rtlRemoved = attachment.Name; } ```