跳至正文

File upload

拖放区域与文件列表。

浏览器
Chrome 123+Firefox 121+Safari 17.5+
层级
1
压缩后大小
2.27 kB
强制布局预算
0 ms
axe 预算
0
支持 SSR
是
公开契约
测试环境

交互示例

File upload

Attachments

Drop files here, or choose files above.

    Up to 3 files · 5 MB each

    "use client";
    import { FileUpload } from "@gunkin/uiify";
    
    export default function Example() {
      return (
        <FileUpload.Root multiple maxFiles={3} maxSize={5000000} className="">
          <FileUpload.HiddenInput name="attachments" aria-label="Attachments" />
          <FileUpload.Trigger as="button" className="">
            Choose files
          </FileUpload.Trigger>
          <FileUpload.Dropzone className="">Drop files here</FileUpload.Dropzone>
          <FileUpload.List className="">
            {(files) =>
              files.map((file, index) => (
                <FileUpload.Item key={file.name} index={index} className="">
                  <span>
                    {file.name} · {(file.size / 1024).toFixed(1)} KB
                  </span>
                  <FileUpload.ItemRemove index={index} aria-label={"Remove " + file.name}>
                    ×
                  </FileUpload.ItemRemove>
                </FileUpload.Item>
              ))
            }
          </FileUpload.List>
        </FileUpload.Root>
      );
    }
    /* File upload — trigger button with dashed dropzone. */
    
    @layer components {
      [data-uiify-file-upload] {
        display: grid;
        gap: var(--space-md);
        inline-size: 100%;
        max-inline-size: 24rem;
      }
    
      [data-uiify-file-upload] [data-part="dropzone"] {
        display: flex;
        align-items: center;
        justify-content: center;
        min-block-size: 8rem;
        padding: var(--space-lg);
        border: 2px dashed var(--input);
        border-radius: var(--radius-xl);
        corner-shape: squircle;
        background-color: var(--secondary);
        color: var(--muted-foreground);
        font-size: var(--text-sm);
        text-align: center;
        transition: var(--transition-colors);
      }
    
      [data-uiify-file-upload] [data-part="dropzone"]:hover,
      [data-uiify-file-upload] [data-part="dropzone"][data-dragging] {
        border-color: var(--primary);
        background-color: color-mix(in oklch, var(--primary) 8%, transparent);
        color: var(--foreground);
      }
    
      [data-uiify-file-upload] [data-part="dropzone"][data-disabled] {
        opacity: 0.5;
        cursor: not-allowed;
      }
    
      [data-uiify-file-upload] [data-part="list"] {
        display: grid;
        gap: var(--space-xs);
        margin: 0;
        padding: 0;
        list-style: none;
      }
    
      [data-uiify-file-upload] [data-part="item"] {
        display: flex;
        align-items: center;
        gap: var(--space-sm);
        padding: var(--space-sm) var(--space-md);
        border: var(--border-width) solid var(--border);
        border-radius: var(--radius-lg);
        corner-shape: squircle;
        background-color: var(--card);
        font-size: var(--text-sm);
      }
    }
    
    @layer components {
      [data-uiify-file-upload] [data-part="file-info"] {
        display: grid;
        gap: 0.25rem;
        min-inline-size: 0;
        flex: 1;
        overflow-wrap: anywhere;
      }
      [data-uiify-file-upload] small {
        color: var(--muted-foreground);
      }
      [data-uiify-file-upload] [data-part="remove"] {
        display: grid;
        place-items: center;
        flex: none;
        inline-size: 2rem;
        block-size: 2rem;
        margin-inline-start: auto;
        border: 0;
        border-radius: 50%;
        background: var(--secondary);
        color: var(--foreground);
        font-size: 1.25rem;
        line-height: 1;
        cursor: pointer;
      }
      [data-uiify-file-upload] [data-part="remove"]:hover {
        background: var(--accent);
      }
      [data-uiify-file-upload] [data-part="remove"]:focus-visible {
        outline: 2px solid var(--ring);
        outline-offset: 2px;
      }
    }
    "use client";
    import { FileUpload } from "@gunkin/uiify";
    
    export default function Example() {
      return (
        <FileUpload.Root
          multiple
          maxFiles={3}
          maxSize={5000000}
          className="
            grid gap-md [inline-size:100%] [max-inline-size:24rem] [&_[data-part=dropzone]]:flex
            [&_[data-part=dropzone]]:items-center [&_[data-part=dropzone]]:justify-center
            [&_[data-part=dropzone]]:[min-block-size:8rem] [&_[data-part=dropzone]]:p-lg
            [&_[data-part=dropzone]]:[border-width:2px] [&_[data-part=dropzone]]:[border-style:dashed]
            [&_[data-part=dropzone]]:border-input [&_[data-part=dropzone]]:rounded-xl
            [&_[data-part=dropzone]]:[corner-shape:squircle] [&_[data-part=dropzone]]:bg-secondary
            [&_[data-part=dropzone]]:text-muted-foreground [&_[data-part=dropzone]]:text-sm
            [&_[data-part=dropzone]]:text-center [&_[data-part=dropzone]]:[transition:var(--transition-colors)]
            [&_[data-part=dropzone]:hover]:border-primary
            [&_[data-part=dropzone]:hover]:[background-color:color-mix(in_oklch,_var(--primary)_8%,_transparent)]
            [&_[data-part=dropzone]:hover]:text-foreground [&_[data-part=dropzone][data-dragging]]:border-primary
            [&_[data-part=dropzone][data-dragging]]:[background-color:color-mix(in_oklch,_var(--primary)_8%,_transparent)]
            [&_[data-part=dropzone][data-dragging]]:text-foreground [&_[data-part=dropzone][data-disabled]]:opacity-50
            [&_[data-part=dropzone][data-disabled]]:cursor-not-allowed [&_[data-part=list]]:grid [&_[data-part=list]]:gap-xs
            [&_[data-part=list]]:m-0 [&_[data-part=list]]:p-0 [&_[data-part=list]]:list-none [&_[data-part=item]]:flex
            [&_[data-part=item]]:items-center [&_[data-part=item]]:gap-sm
            [&_[data-part=item]]:[padding:var(--space-sm)_var(--space-md)]
            [&_[data-part=item]]:border-[length:var(--border-width)] [&_[data-part=item]]:border-solid
            [&_[data-part=item]]:border-border [&_[data-part=item]]:rounded-lg [&_[data-part=item]]:[corner-shape:squircle]
            [&_[data-part=item]]:bg-card [&_[data-part=item]]:text-sm [&_[data-part=file-info]]:grid
            [&_[data-part=file-info]]:[gap:0.25rem] [&_[data-part=file-info]]:[min-inline-size:0]
            [&_[data-part=file-info]]:[flex:1] [&_[data-part=file-info]]:[overflow-wrap:anywhere]
            [&_small]:text-muted-foreground [&_[data-part=remove]]:grid [&_[data-part=remove]]:place-items-center
            [&_[data-part=remove]]:flex-none [&_[data-part=remove]]:[inline-size:2rem]
            [&_[data-part=remove]]:[block-size:2rem] [&_[data-part=remove]]:[margin-inline-start:auto]
            [&_[data-part=remove]]:border-0 [&_[data-part=remove]]:border-current [&_[data-part=remove]]:border-none
            [&_[data-part=remove]]:rounded-[50%] [&_[data-part=remove]]:bg-secondary [&_[data-part=remove]]:text-foreground
            [&_[data-part=remove]]:[font-size:1.25rem] [&_[data-part=remove]]:leading-none
            [&_[data-part=remove]]:cursor-pointer [&_[data-part=remove]:hover]:bg-accent
            [&_[data-part=remove]:focus-visible]:[outline:2px_solid_var(--ring)]
            [&_[data-part=remove]:focus-visible]:[outline-offset:2px]
          "
        >
          <FileUpload.HiddenInput name="attachments" aria-label="Attachments" />
          <FileUpload.Trigger
            as="button"
            className={
              "focus-visible:[outline:none] focus-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--" +
              "ring)_16%,_transparent)] [--uiify-button-rim:rgb(255_255_255_/_20%)] [--uiify-button-wash:light-dark(rgb(" +
              "255_255_255_/_15%),_rgb(255_255_255_/_30%))] relative isolate inline-flex items-center justify-center [ga" +
              "p:0.375rem] [min-block-size:44px] [min-inline-size:44px] py-0 [padding-inline:1.25rem] border-[length:var" +
              "(--border-width)] border-solid border-transparent rounded-[var(--radius-full)] bg-foreground bg-clip-padd" +
              "ing text-background text-base font-[number:var(--weight-medium)] leading-6 no-underline cursor-pointer [t" +
              "ransition:var(--transition-colors)] before:content-[''] before:absolute before:inset-0 before:z-[-1] befo" +
              "re:[border-radius:inherit] before:pointer-events-none after:content-[''] after:absolute after:inset-0 aft" +
              "er:z-[-1] after:[border-radius:inherit] after:pointer-events-none before:[background-color:var(--uiify-bu" +
              "tton-wash)] before:[filter:blur(10px)] before:[translate:0_-50%] before:[clip-path:inset(50%_0_-50%_0_rou" +
              "nd_var(--radius-full))] after:[padding:0.5px] after:[background-image:linear-gradient(to_bottom,_var(--ui" +
              "ify-button-rim),_transparent_75%)] after:[mask:linear-gradient(#fff_0_0)_content-box_exclude,_linear-grad" +
              "ient(#fff_0_0)] [&:is([data-size=sm],[data-size=icon-sm])]:[min-block-size:32px] [&:is([data-size=sm],[da" +
              "ta-size=icon-sm])]:[min-inline-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[padding-inline:0.75" +
              "rem] [&:is([data-size=sm],[data-size=icon-sm])]:[gap:0.25rem] [&:is([data-size=sm],[data-size=icon-sm])]:" +
              "text-sm [&:is([data-size=sm],[data-size=icon-sm])]:leading-5 [&:is([data-size=lg],[data-size=icon-lg])]:[" +
              "min-block-size:56px] [&:is([data-size=lg],[data-size=icon-lg])]:[min-inline-size:56px] [&:is([data-size=l" +
              "g],[data-size=icon-lg])]:[padding-inline:1.75rem] [&:is([data-size=lg],[data-size=icon-lg])]:text-lg [&:i" +
              "s([data-size=lg],[data-size=icon-lg])]:leading-7 [&[data-size^=icon]]:px-0 [@media_(any-hover:_hover)_and" +
              "_(any-pointer:_fine)]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(" +
              "--foreground)_90%,_var(--background))] active:[&:not(:disabled,[data-disabled])]:[background-color:color-" +
              "mix(in_oklch,_var(--foreground)_80%,_var(--background))] disabled:opacity-50 disabled:cursor-not-allowed " +
              "data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed data-[variant=secondary]:[&:where(:not(:che" +
              "cked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-rim:light-dark(rgb(0_0_" +
              "0_/_5%),_rgb(255_255_255_/_10%))] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria" +
              "-pressed=true],[aria-current=page]))]:[--uiify-button-wash:light-dark(rgb(255_255_255_/_20%),_rgb(255_255" +
              "_255_/_5%))] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-" +
              "current=page]))]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] data-[variant" +
              "=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-fore" +
              "ground data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=" +
              "page]))]:[--uiify-button-rim:color-mix(in_oklch,_var(--foreground)_25%,_transparent)] data-[variant=outli" +
              "ne]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[border-color:col" +
              "or-mix(in_oklch,_var(--foreground)_20%,_transparent)] data-[variant=outline]:[&:where(:not(:checked+*,[da" +
              "ta-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent data-[variant=outline]:[&:where(:n" +
              "ot(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=ou" +
              "tline]:before:content-none data-[variant=outline]:after:[inset:calc(-1_*_var(--border-width))] data-[vari" +
              "ant=outline]:after:[padding:var(--border-width)] data-[variant=outline]:[&:where(:not(:checked+*,[data-se" +
              "lected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-" +
              "color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant=ghost]:[&:where(:not(:checke" +
              "d+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent data-[variant=ghost]:[&:whe" +
              "re(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[varia" +
              "nt=ghost]:before:content-none data-[variant=ghost]:after:content-none data-[variant=ghost]:[&:where(:not(" +
              ":checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disab" +
              "led])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant=secondary" +
              "]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disa" +
              "bled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_26%,_transparent)] data-[v" +
              "ariant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[" +
              "--uiify-button-wash:rgb(255_255_255_/_15%)] data-[variant=destructive]:[&:where(:not(:checked+*,[data-sel" +
              "ected],[aria-pressed=true],[aria-current=page]))]:bg-destructive data-[variant=destructive]:text-destruct" +
              "ive-foreground data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[a" +
              "ria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(" +
              "--destructive),_black_20%)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=outline]:[&" +
              ":where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled," +
              "[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any" +
              "-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[ar" +
              "ia-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-" +
              "mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:da" +
              "ta-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))" +
              "]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_20%,_t" +
              "ransparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=destructive]:[&:where(:not" +
              "(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disab" +
              "led])]:[background-color:color-mix(in_oklch,_var(--destructive),_black_12%)] [&:is([data-selected],[aria-" +
              "pressed=true],[aria-current=page])]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [&:is([data-selected],[ar" +
              "ia-pressed=true],[aria-current=page])]:[--uiify-button-wash:rgb(255_255_255_/_15%)] [&:is([data-selected]" +
              ",[aria-pressed=true],[aria-current=page])]:border-transparent [&:is([data-selected],[aria-pressed=true],[" +
              "aria-current=page])]:bg-primary [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:text-prim" +
              "ary-foreground [:checked+&]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [:checked+&]:[--uiify-button-wash" +
              ":rgb(255_255_255_/_15%)] [:checked+&]:border-transparent [:checked+&]:bg-primary [:checked+&]:text-primar" +
              "y-foreground [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[&:is([data-selected],[aria-pressed=true" +
              "],[aria-current=page]):hover:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--" +
              "primary)_88%,_var(--primary-foreground))] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[:checked:n" +
              "ot(:disabled)+&:hover]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground" +
              "))] [:disabled+&]:opacity-50 [:disabled+&]:cursor-not-allowed [&[hidden]]:hidden data-[variant=link]:px-0" +
              " data-[variant=link]:border-0 data-[variant=link]:border-current data-[variant=link]:border-none data-[va" +
              "riant=link]:rounded-none data-[variant=link]:bg-transparent data-[variant=link]:text-primary data-[varian" +
              "t=link]:underline data-[variant=link]:[text-underline-offset:0.2em] data-[variant=link]:active:px-0 data-" +
              "[variant=link]:active:border-0 data-[variant=link]:active:border-current data-[variant=link]:active:borde" +
              "r-none data-[variant=link]:active:rounded-none data-[variant=link]:active:bg-transparent data-[variant=li" +
              "nk]:active:text-primary data-[variant=link]:active:underline data-[variant=link]:active:[text-underline-o" +
              "ffset:0.2em] data-[variant=link]:[min-inline-size:0] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:" +
              "data-[variant=link]:hover:px-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:ho" +
              "ver:border-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-current" +
              " [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-none [@media_(any-h" +
              "over:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:rounded-none [@media_(any-hover:_hover)_a" +
              "nd_(any-pointer:_fine)]:data-[variant=link]:hover:bg-transparent [@media_(any-hover:_hover)_and_(any-poin" +
              "ter:_fine)]:data-[variant=link]:hover:text-primary [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:da" +
              "ta-[variant=link]:hover:underline [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]" +
              ":hover:[text-underline-offset:0.2em] data-[variant=link]:before:content-none data-[variant=link]:after:co" +
              "ntent-none data-[variant=link]:focus-visible:[outline:2px_solid_var(--ring)] data-[variant=link]:focus-vi" +
              "sible:[outline-offset:3px] [[data-uiify-toggle]>input:focus-visible+&]:[box-shadow:0_0_0_var(--ring-width" +
              ")_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[data-uiify-toggle-group]_[data-part=item]>input:fo" +
              "cus-visible+&]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[d" +
              "ata-uiify-modal][data-part=close]&]:border-transparent [[data-uiify-modal][data-part=close]&]:[background" +
              "-color:color-mix(in_oklch,_var(--foreground)_8%,_transparent)] [[data-uiify-modal][data-part=close]&]:tex" +
              "t-foreground [[data-uiify-modal][data-part=close]&:hover]:[background-color:color-mix(in_oklch,_var(--for" +
              "eground)_14%,_transparent)] [[data-uiify-modal][data-part=close]&:active]:[background-color:color-mix(in_" +
              "oklch,_var(--foreground)_20%,_transparent)] [[data-uiify-pagination]_span&:not([data-disabled])]:cursor-d" +
              "efault [[data-uiify-input-group]>[data-part=addon]>&]:[min-inline-size:0] [[data-uiify-input-group]>[data" +
              "-part=addon]>&]:[max-inline-size:100%] [[data-uiify-input-group]>[data-part=addon]>&]:whitespace-normal [" +
              "[data-uiify-input-group]>[data-part=addon]>&]:[overflow-wrap:anywhere] [[data-uiify-item-content]>&]:[jus" +
              "tify-self:start]"
            }
          >
            Choose files
          </FileUpload.Trigger>
          <FileUpload.Dropzone className="">Drop files here</FileUpload.Dropzone>
          <FileUpload.List className="">
            {(files) =>
              files.map((file, index) => (
                <FileUpload.Item key={file.name} index={index} className="">
                  <span>
                    {file.name} · {(file.size / 1024).toFixed(1)} KB
                  </span>
                  <FileUpload.ItemRemove index={index} aria-label={"Remove " + file.name}>
                    ×
                  </FileUpload.ItemRemove>
                </FileUpload.Item>
              ))
            }
          </FileUpload.List>
        </FileUpload.Root>
      );
    }
    /* app.css */
    
    @layer reset, ui, app, tokens, base, demo, components, utilities, theme;
    
    @import "@gunkin/uiify/styles/reset";
    
    @import "@gunkin/uiify/components/behavior.css";
    
    @import "@gunkin/uiify/styles/tokens";
    
    @import "@gunkin/uiify/styles/tailwind";
    
    @import "tailwindcss/utilities.css";
    
    @theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }
    
    @source inline('grid gap-md [inline-size:100%] [max-inline-size:24rem] [&_[data-part=dropzone]]:flex [&_[data-part=dropzone]]:items-center [&_[data-part=dropzone]]:justify-center [&_[data-part=dropzone]]:[min-block-size:8rem] [&_[data-part=dropzone]]:p-lg [&_[data-part=dropzone]]:[border-width:2px] [&_[data-part=dropzone]]:[border-style:dashed] [&_[data-part=dropzone]]:border-input [&_[data-part=dropzone]]:rounded-xl [&_[data-part=dropzone]]:[corner-shape:squircle] [&_[data-part=dropzone]]:bg-secondary [&_[data-part=dropzone]]:text-muted-foreground [&_[data-part=dropzone]]:text-sm [&_[data-part=dropzone]]:text-center [&_[data-part=dropzone]]:[transition:var(--transition-colors)] [&_[data-part=dropzone]:hover]:border-primary [&_[data-part=dropzone]:hover]:[background-color:color-mix(in_oklch,_var(--primary)_8%,_transparent)] [&_[data-part=dropzone]:hover]:text-foreground [&_[data-part=dropzone][data-dragging]]:border-primary [&_[data-part=dropzone][data-dragging]]:[background-color:color-mix(in_oklch,_var(--primary)_8%,_transparent)] [&_[data-part=dropzone][data-dragging]]:text-foreground [&_[data-part=dropzone][data-disabled]]:opacity-50 [&_[data-part=dropzone][data-disabled]]:cursor-not-allowed [&_[data-part=list]]:grid [&_[data-part=list]]:gap-xs [&_[data-part=list]]:m-0 [&_[data-part=list]]:p-0 [&_[data-part=list]]:list-none [&_[data-part=item]]:flex [&_[data-part=item]]:items-center [&_[data-part=item]]:gap-sm [&_[data-part=item]]:[padding:var(--space-sm)_var(--space-md)] [&_[data-part=item]]:border-[length:var(--border-width)] [&_[data-part=item]]:border-solid [&_[data-part=item]]:border-border [&_[data-part=item]]:rounded-lg [&_[data-part=item]]:[corner-shape:squircle] [&_[data-part=item]]:bg-card [&_[data-part=item]]:text-sm [&_[data-part=file-info]]:grid [&_[data-part=file-info]]:[gap:0.25rem] [&_[data-part=file-info]]:[min-inline-size:0] [&_[data-part=file-info]]:[flex:1] [&_[data-part=file-info]]:[overflow-wrap:anywhere] [&_small]:text-muted-foreground [&_[data-part=remove]]:grid [&_[data-part=remove]]:place-items-center [&_[data-part=remove]]:flex-none [&_[data-part=remove]]:[inline-size:2rem] [&_[data-part=remove]]:[block-size:2rem] [&_[data-part=remove]]:[margin-inline-start:auto] [&_[data-part=remove]]:border-0 [&_[data-part=remove]]:border-current [&_[data-part=remove]]:border-none [&_[data-part=remove]]:rounded-[50%] [&_[data-part=remove]]:bg-secondary [&_[data-part=remove]]:text-foreground [&_[data-part=remove]]:[font-size:1.25rem] [&_[data-part=remove]]:leading-none [&_[data-part=remove]]:cursor-pointer [&_[data-part=remove]:hover]:bg-accent [&_[data-part=remove]:focus-visible]:[outline:2px_solid_var(--ring)] [&_[data-part=remove]:focus-visible]:[outline-offset:2px] focus-visible:[outline:none] focus-visible:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [--uiify-button-rim:rgb(255_255_255_/_20%)] [--uiify-button-wash:light-dark(rgb(255_255_255_/_15%),_rgb(255_255_255_/_30%))] relative isolate inline-flex items-center justify-center [gap:0.375rem] [min-block-size:44px] [min-inline-size:44px] py-0 [padding-inline:1.25rem] border-[length:var(--border-width)] border-solid border-transparent rounded-[var(--radius-full)] bg-foreground bg-clip-padding text-background text-base font-[number:var(--weight-medium)] leading-6 no-underline cursor-pointer [transition:var(--transition-colors)] before:absolute before:inset-0 before:z-[-1] before:[border-radius:inherit] before:pointer-events-none after:absolute after:inset-0 after:z-[-1] after:[border-radius:inherit] after:pointer-events-none before:[background-color:var(--uiify-button-wash)] before:[filter:blur(10px)] before:[translate:0_-50%] before:[clip-path:inset(50%_0_-50%_0_round_var(--radius-full))] after:[padding:0.5px] after:[background-image:linear-gradient(to_bottom,_var(--uiify-button-rim),_transparent_75%)] after:[mask:linear-gradient(#fff_0_0)_content-box_exclude,_linear-gradient(#fff_0_0)] [&:is([data-size=sm],[data-size=icon-sm])]:[min-block-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[min-inline-size:32px] [&:is([data-size=sm],[data-size=icon-sm])]:[padding-inline:0.75rem] [&:is([data-size=sm],[data-size=icon-sm])]:[gap:0.25rem] [&:is([data-size=sm],[data-size=icon-sm])]:text-sm [&:is([data-size=sm],[data-size=icon-sm])]:leading-5 [&:is([data-size=lg],[data-size=icon-lg])]:[min-block-size:56px] [&:is([data-size=lg],[data-size=icon-lg])]:[min-inline-size:56px] [&:is([data-size=lg],[data-size=icon-lg])]:[padding-inline:1.75rem] [&:is([data-size=lg],[data-size=icon-lg])]:text-lg [&:is([data-size=lg],[data-size=icon-lg])]:leading-7 [&[data-size^=icon]]:px-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_90%,_var(--background))] active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_80%,_var(--background))] disabled:opacity-50 disabled:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-rim:light-dark(rgb(0_0_0_/_5%),_rgb(255_255_255_/_10%))] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-wash:light-dark(rgb(255_255_255_/_20%),_rgb(255_255_255_/_5%))] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-rim:color-mix(in_oklch,_var(--foreground)_25%,_transparent)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[border-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=outline]:before:content-none data-[variant=outline]:after:[inset:calc(-1_*_var(--border-width))] data-[variant=outline]:after:[padding:var(--border-width)] data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-transparent data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:text-foreground data-[variant=ghost]:before:content-none data-[variant=ghost]:after:content-none data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_16%,_transparent)] data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_26%,_transparent)] data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:[--uiify-button-wash:rgb(255_255_255_/_15%)] data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:bg-destructive data-[variant=destructive]:text-destructive-foreground data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:active:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--destructive),_black_20%)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=outline]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=ghost]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_10%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=secondary]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=destructive]:[&:where(:not(:checked+*,[data-selected],[aria-pressed=true],[aria-current=page]))]:hover:[&:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--destructive),_black_12%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:[--uiify-button-wash:rgb(255_255_255_/_15%)] [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:border-transparent [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:bg-primary [&:is([data-selected],[aria-pressed=true],[aria-current=page])]:text-primary-foreground [:checked+&]:[--uiify-button-rim:rgb(255_255_255_/_20%)] [:checked+&]:[--uiify-button-wash:rgb(255_255_255_/_15%)] [:checked+&]:border-transparent [:checked+&]:bg-primary [:checked+&]:text-primary-foreground [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[&:is([data-selected],[aria-pressed=true],[aria-current=page]):hover:not(:disabled,[data-disabled])]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:[:checked:not(:disabled)+&:hover]:[background-color:color-mix(in_oklch,_var(--primary)_88%,_var(--primary-foreground))] [:disabled+&]:opacity-50 [:disabled+&]:cursor-not-allowed [&[hidden]]:hidden data-[variant=link]:px-0 data-[variant=link]:border-0 data-[variant=link]:border-current data-[variant=link]:border-none data-[variant=link]:rounded-none data-[variant=link]:bg-transparent data-[variant=link]:text-primary data-[variant=link]:underline data-[variant=link]:[text-underline-offset:0.2em] data-[variant=link]:active:px-0 data-[variant=link]:active:border-0 data-[variant=link]:active:border-current data-[variant=link]:active:border-none data-[variant=link]:active:rounded-none data-[variant=link]:active:bg-transparent data-[variant=link]:active:text-primary data-[variant=link]:active:underline data-[variant=link]:active:[text-underline-offset:0.2em] data-[variant=link]:[min-inline-size:0] [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:px-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-0 [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-current [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:border-none [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:rounded-none [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:bg-transparent [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:text-primary [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:underline [@media_(any-hover:_hover)_and_(any-pointer:_fine)]:data-[variant=link]:hover:[text-underline-offset:0.2em] data-[variant=link]:before:content-none data-[variant=link]:after:content-none data-[variant=link]:focus-visible:[outline:2px_solid_var(--ring)] data-[variant=link]:focus-visible:[outline-offset:3px] [[data-uiify-toggle]>input:focus-visible+&]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[data-uiify-toggle-group]_[data-part=item]>input:focus-visible+&]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [[data-uiify-modal][data-part=close]&]:border-transparent [[data-uiify-modal][data-part=close]&]:[background-color:color-mix(in_oklch,_var(--foreground)_8%,_transparent)] [[data-uiify-modal][data-part=close]&]:text-foreground [[data-uiify-modal][data-part=close]&:hover]:[background-color:color-mix(in_oklch,_var(--foreground)_14%,_transparent)] [[data-uiify-modal][data-part=close]&:active]:[background-color:color-mix(in_oklch,_var(--foreground)_20%,_transparent)] [[data-uiify-pagination]_span&:not([data-disabled])]:cursor-default [[data-uiify-input-group]>[data-part=addon]>&]:[min-inline-size:0] [[data-uiify-input-group]>[data-part=addon]>&]:[max-inline-size:100%] [[data-uiify-input-group]>[data-part=addon]>&]:whitespace-normal [[data-uiify-input-group]>[data-part=addon]>&]:[overflow-wrap:anywhere] [[data-uiify-item-content]>&]:[justify-self:start]');
    
    @source inline("before:content-[''] after:content-['']");
    
    @layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }
    
    /* Authored animation and registered properties used by the Tailwind skin.
     * Visual rules belong in utility recipes; only at-rule definitions live here. */
    @layer components {
      @keyframes uiify-presence-in {
        from {
          opacity: 0;
          scale: var(--presence-scale);
        }
      }
    }
    
    @layer components {
      @keyframes uiify-presence-out {
        to {
          opacity: 0;
          scale: var(--presence-scale);
        }
      }
    }
    
    @property --uiify-spinner-tail {
      syntax: "<angle>";
      inherits: false;
      initial-value: 0deg;
    }
    
    @property --uiify-spinner-length {
      syntax: "<angle>";
      inherits: false;
      initial-value: 36deg;
    }
    
    @layer components {
      @keyframes uiify-spinner-rotate {
        to {
          transform: rotate(360deg);
        }
      }
    }
    
    @layer components {
      @keyframes uiify-spinner-orbit {
        0% {
          --uiify-spinner-tail: 0deg;
          --uiify-spinner-length: 36deg;
        }
    
        50% {
          --uiify-spinner-tail: 90deg;
          --uiify-spinner-length: 324deg;
        }
    
        100% {
          --uiify-spinner-tail: 360deg;
          --uiify-spinner-length: 36deg;
        }
      }
    }
    
    @layer components {
      @keyframes uiify-skeleton-pulse {
        50% {
          opacity: 0.45;
        }
      }
    }
    
    @layer components {
      @keyframes uiify-skeleton-shimmer {
        to {
          background-position: -200% 0;
        }
      }
    }
    
    @layer components {
      @keyframes uiify-skeleton-reveal {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }
    }
    
    @property --candle-body-height {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 0%;
    }
    
    @property --candle-body-top {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 50%;
    }
    
    @property --candle-slot {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 100%;
    }
    
    @property --candle-wick-height {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 0%;
    }
    
    @property --candle-wick-top {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 50%;
    }
    
    @property --candle-x {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 0%;
    }
    
    @property --candle-scale {
      syntax: "<number>";
      inherits: true;
      initial-value: 1;
    }
    
    @property --line-y {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 50%;
    }
    
    @property --line-prev-y {
      syntax: "<percentage>";
      inherits: true;
      initial-value: 50%;
    }
    
    @property --line-count {
      syntax: "<integer>";
      inherits: false;
      initial-value: 1;
    }
    
    @property --line-scale {
      syntax: "<number>";
      inherits: true;
      initial-value: 1;
    }
    
    @layer components {
      @keyframes uiify-otp-input-caret-blink {
        50% {
          opacity: 0;
        }
      }
    }

    API

    FileUpload.Root

    属性类型默认值说明
    childrenReactNode—文件上传组成部分:隐藏输入框、触发器、拖放区域和列表。
    valuereadonly File[]—当前文件,使组件受控。
    defaultValuereadonly File[][]非受控组件的初始文件。
    onValueChange(files: File[]) => void—选择变化时,使用已接受的文件调用。
    onReject(rejections: FileRejection[]) => void—使用未通过校验的文件及原因调用。
    acceptstring[][]接受的文件类型,以扩展名或MIME类型表示。
    maxFilesnumber—可同时保留的最大文件数。
    maxSizenumber—接受的最大文件大小,单位为字节。
    minSizenumber—接受的最小文件大小,单位为字节。
    multiplebooleanfalse允许选择器选择多个文件。
    disabledbooleanfalse禁用选择器、拖放区域和移除按钮。

    FileUpload.HiddenInput

    属性类型默认值说明
    classNamestring—应用于原生文件输入框的类名。

    FileUpload.Trigger

    属性类型默认值说明
    childrenReactNode—打开文件选择器的控件内容。
    classNamestring—应用于触发器元素的类名。
    renderReactElement | ((props, state) => ReactElement)—替换渲染元素,同时保留行为和无障碍连接关系。

    FileUpload.Dropzone

    属性类型默认值说明
    childrenReactNode—拖放目标的内容。
    classNamestring—应用于拖放区域元素的类名。
    renderReactElement | ((props, state) => ReactElement)—替换渲染元素,同时保留行为和无障碍连接关系。

    FileUpload.List

    属性类型默认值说明
    childrenReactNode | ((files: readonly File[]) => ReactNode)—从实时列表渲染已接受的文件。受控值变化和外部重置会立即反映。
    classNamestring—应用于列表元素的类名。

    FileUpload.Item

    属性类型默认值说明
    childrenReactNode—描述文件的内容,例如文件名和大小。
    classNamestring—应用于项目元素的类名。
    index*number—此项目对应的文件位置。
    renderReactElement | ((props, state) => ReactElement)—替换渲染元素,同时保留行为和无障碍连接关系。

    FileUpload.ItemRemove

    属性类型默认值说明
    classNamestring—应用于移除按钮的类名。
    index*number—此按钮移除的文件位置。

    FileRejection

    属性类型默认值说明
    file*File—未被接受的文件。
    reason*"accept" | "max-size" | "max-files"—文件未通过哪条规则。

    键盘

    按键操作
    Enter / Space通过Trigger打开文件选择器,或移除已聚焦的文件
    Tab在选择器触发器与文件移除控件之间移动

    无障碍

    为HiddenInput提供无障碍标签。List接收已接受的文件,渲染文件名、大小及带标签的移除按钮。Root支持受控value、累计maxFiles、maxSize和accept校验;onReject报告被拒绝的文件。禁用根元素后,选择、拖放和移除操作均被阻止。文件处理需要水合。

    样式钩子

    data-uiify-file-uploaddata-partdata-disableddata-state
    本页由机器翻译,尚未经人工审核。