77namespace Microsoft . AspNetCore . Components . Web . Media ;
88
99/// <summary>
10- /// A component that provides a button which, when clicked, downloads the provided media source
10+ /// A component that provides a link which, when activated ( clicked) , downloads the provided media source
1111/// either via a save-as dialog or directly, using the same BinaryMedia pipeline as <see cref="Image"/> and <see cref="Video"/>.
1212/// </summary>
1313/// <remarks>
1414/// Unlike <see cref="Image"/> and <see cref="Video"/>, this component does not automatically load the media.
15- /// It defers loading until the user clicks the button . The stream is then materialized, optionally cached,
16- /// and a client-side download is triggered.
15+ /// It defers loading until the user activates the link . The stream is then materialized (no caching is performed for downloads)
16+ /// and a client-side download is triggered. Developers can style the link as a button via CSS (e.g., with a framework class).
1717/// </remarks>
1818public sealed class FileDownload : MediaComponentBase
1919{
@@ -23,12 +23,12 @@ public sealed class FileDownload : MediaComponentBase
2323 [ Parameter , EditorRequired ] public string FileName { get ; set ; } = default ! ;
2424
2525 /// <summary>
26- /// Provides custom button text. Defaults to "Download".
26+ /// Provides custom link text. Defaults to "Download".
2727 /// </summary>
28- [ Parameter ] public string ? ButtonText { get ; set ; }
28+ [ Parameter ] public string ? Text { get ; set ; }
2929
3030 /// <inheritdoc />
31- protected override string TagName => "button " ;
31+ protected override string TagName => "a " ;
3232
3333 /// <inheritdoc />
3434 protected override string TargetAttributeName => string . Empty ; // Not used – object URL not tracked for downloads.
@@ -40,13 +40,13 @@ public sealed class FileDownload : MediaComponentBase
4040 protected override bool ShouldAutoLoad => false ;
4141
4242 /// <summary>
43- /// Builds the button element with click handler wiring.
43+ /// Builds the anchor element with click handler wiring. The anchor is given an inert href (if one is not supplied)
44+ /// and the click default action is prevented so navigation does not occur. Styling into a button shape is left to the user.
4445 /// </summary>
4546 protected override void BuildRenderTree ( RenderTreeBuilder builder )
4647 {
4748 builder . OpenElement ( 0 , TagName ) ;
4849
49- // Removed object URL attribute emission; not needed for downloads.
5050 builder . AddAttribute ( 1 , MarkerAttributeName , "" ) ;
5151
5252 if ( IsLoading )
@@ -58,12 +58,19 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
5858 builder . AddAttribute ( 2 , "data-state" , "error" ) ;
5959 }
6060
61- builder . AddAttribute ( 3 , "type" , "button" ) ;
61+ builder . AddAttribute ( 3 , "href" , "javascript:void(0)" ) ;
62+
6263 builder . AddAttribute ( 4 , "onclick" , EventCallback . Factory . Create ( this , OnClickAsync ) ) ;
63- builder . AddMultipleAttributes ( 5 , AdditionalAttributes ) ;
64- builder . AddElementReferenceCapture ( 6 , elementReference => Element = elementReference ) ;
6564
66- builder . AddContent ( 7 , ButtonText ?? "Download" ) ;
65+ if ( AdditionalAttributes ? . ContainsKey ( "href" ) == true )
66+ {
67+ AdditionalAttributes . Remove ( "href" ) ;
68+ }
69+ builder . AddMultipleAttributes ( 6 , AdditionalAttributes ) ;
70+
71+ builder . AddElementReferenceCapture ( 7 , elementReference => Element = elementReference ) ;
72+
73+ builder . AddContent ( 8 , Text ?? "Download" ) ;
6774
6875 builder . CloseElement ( ) ;
6976 }
0 commit comments