PdfViewer
BitPdfViewer is a native pure-C# pdf viewer component for Blazor. It parses pdf files and renders pages as plain HTML/CSS DOM with no browser pdf plugin and no js library dependency, offering page navigation, zoom, rotation, search, thumbnails, bookmarks, download, print and fullscreen out of the box.
Notes
To use this component, you need to install the
Bit.BlazorUI.Extras
nuget package, as described in the Optional steps of the
Getting started page.
Usage
Basic
<InputFile OnChange="OnBasicFileChange" accept=".pdf,application/pdf" /> <BitPdfViewer Source="basicSource" />@code { private BitPdfSource basicSource = BitPdfSource.FromUrl("url-to-the-pdf-file.pdf", "file-name.pdf"); // or from in-memory bytes: // private BitPdfSource basicSource = BitPdfSource.FromBytes(pdfBytes, "file-name.pdf"); private async Task OnBasicFileChange(InputFileChangeEventArgs e) { if (e.FileCount == 0) return; const long maxSize = 512 * 1024 * 1024; if (e.File.Size <= 0 || e.File.Size > maxSize) return; using var stream = e.File.OpenReadStream(maxAllowedSize: maxSize); var bytes = new byte[(int)e.File.Size]; await stream.ReadExactlyAsync(bytes); basicSource = BitPdfSource.FromBytes(bytes, e.File.Name); } }
Toolbar & Height
<BitButton IsEnabled="plainSource is null" OnClick='() => plainSource = BitPdfSource.FromUrl("url-to-the-pdf-file.pdf", "file-name.pdf")'>Load document</BitButton> <BitPdfViewer Source="plainSource" ShowToolbar="false" Height="600px" />@code { private BitPdfSource? plainSource; }
Canvas render mode
<BitButton IsEnabled="canvasSource is null" OnClick='() => canvasSource = BitPdfSource.FromUrl("url-to-the-pdf-file.pdf", "file-name.pdf")'>Load document</BitButton> <InputFile OnChange="OnCanvasFileChange" accept=".pdf,application/pdf" /> <BitPdfViewer Source="canvasSource" RenderMode="BitPdfRenderMode.Canvas" />@code { private BitPdfSource? canvasSource; private async Task OnCanvasFileChange(InputFileChangeEventArgs e) { if (e.FileCount == 0) return; const long maxSize = 512 * 1024 * 1024; if (e.File.Size <= 0 || e.File.Size > maxSize) return; using var stream = e.File.OpenReadStream(maxAllowedSize: maxSize); var bytes = new byte[(int)e.File.Size]; await stream.ReadExactlyAsync(bytes); canvasSource = BitPdfSource.FromBytes(bytes, e.File.Name); } }
Events
<BitButton IsEnabled="eventsSource is null" OnClick='() => eventsSource = BitPdfSource.FromUrl("url-to-the-pdf-file.pdf", "file-name.pdf")'>Load document</BitButton> <BitPdfViewer Source="eventsSource" OnDocumentLoaded='() => eventsLog.Add("Document loaded")' OnPageChanged='p => eventsLog.Add($"Page changed: {p}")' OnError='e => eventsLog.Add($"Error: {e}")' /> <div>Events:</div> <div style="max-height:8rem;overflow:auto"> @foreach (var log in Enumerable.Reverse(eventsLog).Take(5)) { <div>@log</div> } </div>@code { private BitPdfSource? eventsSource; private readonly List<string> eventsLog = []; }
Public API
<BitButton IsEnabled="publicApiSource is null" OnClick='() => publicApiSource = BitPdfSource.FromUrl("url-to-the-pdf-file.pdf", "file-name.pdf")'>Load document</BitButton> <div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:center"> <BitButton OnClick="() => pdfViewerRef.GoToPage(1)">First</BitButton> <BitButton OnClick="() => pdfViewerRef.PrevPage()">Prev</BitButton> <BitTag Variant="BitVariant.Outline" Text="@($"{pdfViewerRef?.CurrentPage}/{pdfViewerRef?.PageCount}")" Color="BitColor.Info" /> <BitButton OnClick="() => pdfViewerRef.NextPage()">Next</BitButton> <BitButton OnClick="() => pdfViewerRef.GoToPage(pdfViewerRef.PageCount)">Last</BitButton> <BitButton OnClick="() => pdfViewerRef.ZoomOut()">Zoom -</BitButton> <BitButton OnClick="() => pdfViewerRef.ZoomIn()">Zoom +</BitButton> <BitButton OnClick="() => pdfViewerRef.RotateClockwise()">Rotate</BitButton> <BitButton OnClick="() => pdfViewerRef.Print()">Print</BitButton> </div> @* BackgroundRendering offloads parse/render to a worker thread when the runtime has one (Blazor Server, or a WASM app built with WasmEnableThreads). *@ <BitPdfViewer @ref="pdfViewerRef" BackgroundRendering Source="publicApiSource" ShowToolbar="false" OnDocumentLoaded="StateHasChanged" OnPageChanged="_ => StateHasChanged()" />@code { private BitPdfSource? publicApiSource; private BitPdfViewer pdfViewerRef = default!; }
API
BitPdfViewer parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| Source | BitPdfSource? | null | The document to display. |
| Height | string? | null | The CSS height of the viewer container. When not set, the viewer height is responsive: capped at 780px and shrinking to fit the viewport on small screens. |
| ShowToolbar | bool | true | Whether the toolbar is shown. |
| InitialZoomMode | BitPdfZoomMode | BitPdfZoomMode.FitWidth | The initial zoom behavior. |
| TextCoalescing | BitPdfTextCoalescing | BitPdfTextCoalescing.Exact | How painted text is emitted. Compact merges same-line, same-style runs into one span per visual line (far fewer DOM nodes on per-glyph pdfs). |
| RenderMode | BitPdfRenderMode | BitPdfRenderMode.Html | How page content is painted. Canvas replays a display list onto a per-page canvas, while Html (the default) renders prerenderable positioned DOM. |
| BackgroundRendering | bool | false | Offloads document parsing and page rendering to a background thread so scrolling and navigation stay responsive while a complex page renders. Only has an effect when the runtime provides a spare thread (Blazor Server, or a Blazor WebAssembly app built with WasmEnableThreads); on the default single-threaded WebAssembly runtime it is a safe no-op. |
| OnDocumentLoaded | EventCallback | The callback for when a document has finished loading. | |
| OnPageChanged | EventCallback<int> | The callback for when the focused page changes (with the 1-based page number). | |
| OnError | EventCallback<string> | The callback for when loading or rendering fails, with the error message. | |
| OnWarnings | EventCallback<IReadOnlyList<string>> | The callback raised after a document loads with any non-fatal diagnostics (e.g. a damaged file whose cross-reference table had to be rebuilt). | |
| OnPasswordRequested | Func<Task<string?>>? | null | Invoked when an encrypted document needs a password. Return the password to retry, or null/empty to cancel. If unset, a password error surfaces through OnError instead. |
BitPdfViewer public members
| Name | Type | Default value | Description |
|---|---|---|---|
| PageCount | int | The number of pages of the current document. | |
| CurrentPage | int | The currently focused page (1-based). | |
| Zoom | double | The current zoom factor (1 means 100%). | |
| HasOutline | bool | Whether the document exposes any bookmarks. | |
| GoToPage | Task GoToPage(int pageNumber) | Navigates to the provided page number (1-based). | |
| NextPage | Task NextPage() | Navigates to the next page. | |
| PrevPage | Task PrevPage() | Navigates to the previous page. | |
| ZoomIn | Task ZoomIn() | Zooms in by 20%. | |
| ZoomOut | Task ZoomOut() | Zooms out by 20%. | |
| SetZoomMode | Task SetZoomMode(BitPdfZoomMode mode) | Sets the zoom mode (fit-width, fit-page, actual size or custom). | |
| RotateClockwise | Task RotateClockwise() | Rotates all pages 90 degrees clockwise. | |
| Download | Task Download() | Downloads the original document bytes. | |
| Task Print() | Opens the browser print dialog with all pages of the document. | ||
| ToggleFullscreen | Task ToggleFullscreen() | Toggles the fullscreen mode of the viewer. | |
| RenderPageHtml | string RenderPageHtml(int pageNumber) | Renders a single page (1-based) to self-contained HTML, or an empty string when no document is loaded or the number is out of range. | |
| ExtractPageText | string ExtractPageText(int pageNumber) | Extracts the visible text of a single page (1-based) for search or copy, or an empty string when unavailable. |
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. |
| 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. |
| Id | string? | null | Gets or sets the unique identifier for the component's root element. |
| IsEnabled | bool | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. |
| 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. |
BitPdfSource properties
Identifies where a pdf document is loaded from. A source is either a byte buffer already in memory (BitPdfSource.FromBytes), or a URL the document can be fetched from (BitPdfSource.FromUrl).
| Name | Type | Default value | Description |
|---|---|---|---|
| Bytes | byte[]? | null | Raw document bytes, when the source is an in-memory buffer. |
| Url | string? | null | The URL to fetch the document from, when the source is remote. |
| FileName | string? | null | An optional display name (e.g. the original file name). |
| Password | string? | null | The password to open an encrypted document, if known up front (also see the WithPassword method). |
BitPdfZoomMode enum
| Name | Value | Description |
|---|---|---|
| Custom | 0 | An explicit zoom factor is applied (the user picked a percentage). |
| FitWidth | 1 | Each page is scaled so its width fills the viewport. |
| FitPage | 2 | Each page is scaled so the whole page fits in the viewport. |
| ActualSize | 3 | Pages are shown at their natural size (one CSS pixel per point). |
BitPdfRenderMode enum
| Name | Value | Description |
|---|---|---|
| Html | 0 | Pages render to positioned HTML/CSS DOM (the default). Fully prerenderable and crisp at any zoom. |
| Canvas | 1 | Page content is painted onto a per-page canvas by replaying a display list produced by the C# engine. Far fewer DOM nodes; selection, search and links still work through the DOM text layer, and zoom changes re-rasterize the canvases so text stays crisp. Requires JavaScript, so no prerender. |
BitPdfTextCoalescing enum
| Name | Value | Description |
|---|---|---|
| Exact | 0 | Every show-text run keeps its own positioned span, so each glyph run lands at its exact pdf-computed position. Highest fidelity, but per-glyph pdfs emit one span per character. |
| Compact | 1 | Adjacent runs on the same baseline with identical style are merged into one span per visual line. Dramatically fewer DOM nodes on per-glyph pdfs, at the cost of small intra-line position drift. Rotated text is never coalesced and stays exact. |
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
You can give us your feedback through our GitHub repo by filing a new Issue or starting a new Discussion.
Or you can review / edit this page on GitHub.