Open demo

CSS code

HTML
<article class="file">
  <span class="type fig" aria-hidden="true"><b>FIG</b></span>
  <div class="info">
    <h2>brand-system-v4.fig</h2>
    <p class="sub">18.4 MB of 42.1 MB · 12 seconds left</p>
    <div class="bar" role="progressbar" aria-label="Uploading brand-system-v4.fig" aria-valuemin="0" aria-valuemax="100" aria-valuenow="44"><i style="width:44%"></i></div>
  </div>
  <div class="act"><button type="button" aria-label="Cancel upload of brand-system-v4.fig"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button></div>
</article>

<article class="file">
  <span class="type pdf" aria-hidden="true"><b>PDF</b></span>
  <div class="info">
    <h2>2026-annual-report.pdf</h2>
    <p class="sub"><span class="done">Uploaded</span> · 3.8 MB · 2 minutes ago</p>
  </div>
  <div class="act">
    <button type="button" aria-label="Download 2026-annual-report.pdf"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4v11M7 11l5 5 5-5M5 20h14"/></svg></button>
    <button type="button" aria-label="Delete 2026-annual-report.pdf"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 7h14M9 7V5h6v2M7 7l1 13h8l1-13"/></svg></button>
  </div>
</article>

<article class="file">
  <span class="type zip" aria-hidden="true"><b>ZIP</b></span>
  <div class="info">
    <h2>site-backup-aug.zip</h2>
    <p class="sub"><span class="fail">Upload failed</span> · file exceeds the 100 MB limit</p>
  </div>
  <div class="act">
    <button type="button" aria-label="Retry upload of site-backup-aug.zip"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 12a8 8 0 11-2.3-5.7"/><path d="M20 4v5h-5"/></svg></button>
    <button type="button" aria-label="Remove site-backup-aug.zip"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
  </div>
</article>
CSS
/* File cards in three states: uploading (progress bar), uploaded and failed. The file-type badge
   colour comes from --c; the bar is a div with role="progressbar" and its value in aria-valuenow. */
.file{width:400px;max-width:100%;padding:14px 16px;display:flex;align-items:center;gap:14px;
  background:#fff;border:1px solid #e9ecf1;border-radius:16px;transition:box-shadow .18s}
.file:hover{box-shadow:0 10px 26px -18px rgba(16,24,40,.28)}
.file svg{display:block}
.file .type{width:42px;height:50px;flex-shrink:0;border-radius:7px;position:relative;display:grid;
  place-items:end center;padding-bottom:7px;background:#f2f4f7}
.file .type::after{content:"";position:absolute;top:0;right:0;border-width:0 12px 12px 0;border-style:solid;
  border-color:#fff #e4e7ec}
.file .type b{font-size:.6rem;font-weight:800;letter-spacing:.05em;color:#fff;background:var(--c);
  padding:2px 6px;border-radius:4px}
.file .pdf{--c:#dc2626}
.file .fig{--c:#9333ea}
.file .zip{--c:#0e7490}
.file .info{flex:1;min-width:0}
.file h2{font-size:.9rem;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.file .sub{font-size:.79rem;color:#667085}
.file .bar{height:5px;border-radius:99px;background:#eef0f4;margin-top:9px;overflow:hidden}
.file .bar i{display:block;height:100%;border-radius:99px;background:#4f46e5}
.file .done{color:#15803d;font-weight:600}
.file .fail{color:#b91c1c;font-weight:600}
.file .act{flex-shrink:0;display:flex;gap:5px}
.file .act button{width:30px;height:30px;border:0;background:none;border-radius:8px;cursor:pointer;
  color:#667085;display:grid;place-items:center}
.file .act button:hover{background:#f2f4f7;color:#344054}
.file .act button:focus-visible{outline:2px solid #4f46e5;outline-offset:1px}
.file .act svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2.1}
@media (prefers-reduced-motion:reduce){.file{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<article class="card file">
  <div class="card-body d-flex align-items-center">
    <span class="type fig" aria-hidden="true"><span class="badge">FIG</span></span>
    <div class="flex-grow-1 min-w-0">
      <h2 class="card-title text-truncate">brand-system-v4.fig</h2>
      <p class="card-text mb-0">18.4 MB of 42.1 MB · 12 seconds left</p>
      <div class="progress" role="progressbar" aria-label="Uploading brand-system-v4.fig" aria-valuemin="0" aria-valuemax="100" aria-valuenow="44"><div class="progress-bar" style="width:44%"></div></div>
    </div>
    <div class="d-flex gap-1 flex-shrink-0"><button type="button" class="btn btn-icon" aria-label="Cancel upload of brand-system-v4.fig"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button></div>
  </div>
</article>

<article class="card file">
  <div class="card-body d-flex align-items-center">
    <span class="type pdf" aria-hidden="true"><span class="badge">PDF</span></span>
    <div class="flex-grow-1 min-w-0">
      <h2 class="card-title text-truncate">2026-annual-report.pdf</h2>
      <p class="card-text mb-0"><span class="done">Uploaded</span> · 3.8 MB · 2 minutes ago</p>
    </div>
    <div class="d-flex gap-1 flex-shrink-0">
      <button type="button" class="btn btn-icon" aria-label="Download 2026-annual-report.pdf"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4v11M7 11l5 5 5-5M5 20h14"/></svg></button>
      <button type="button" class="btn btn-icon" aria-label="Delete 2026-annual-report.pdf"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 7h14M9 7V5h6v2M7 7l1 13h8l1-13"/></svg></button>
    </div>
  </div>
</article>

<article class="card file">
  <div class="card-body d-flex align-items-center">
    <span class="type zip" aria-hidden="true"><span class="badge">ZIP</span></span>
    <div class="flex-grow-1 min-w-0">
      <h2 class="card-title text-truncate">site-backup-aug.zip</h2>
      <p class="card-text mb-0"><span class="fail">Upload failed</span> · file exceeds the 100 MB limit</p>
    </div>
    <div class="d-flex gap-1 flex-shrink-0">
      <button type="button" class="btn btn-icon" aria-label="Retry upload of site-backup-aug.zip"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 12a8 8 0 11-2.3-5.7"/><path d="M20 4v5h-5"/></svg></button>
      <button type="button" class="btn btn-icon" aria-label="Remove site-backup-aug.zip"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
    </div>
  </div>
</article>
CSS
/* Bootstrap .card + .progress + .btn. The file-type badge colour comes from --c;
   the progress track and bar are recoloured through --bs-progress-* variables. */
.file{--bs-card-border-color:#e9ecf1;--bs-card-border-radius:16px;--bs-card-spacer-y:14px;--bs-card-spacer-x:16px;
  width:400px;max-width:100%;transition:box-shadow .18s}
.file:hover{box-shadow:0 10px 26px -18px rgba(16,24,40,.28)}
.file .card-body{gap:14px}
.file .type{width:42px;height:50px;flex-shrink:0;border-radius:7px;position:relative;display:grid;
  place-items:end center;padding-bottom:7px;background:#f2f4f7}
.file .type::after{content:"";position:absolute;top:0;right:0;border-width:0 12px 12px 0;border-style:solid;
  border-color:#fff #e4e7ec}
.file .type .badge{--bs-badge-font-size:.6rem;--bs-badge-font-weight:800;--bs-badge-padding-x:6px;--bs-badge-padding-y:2px;
  --bs-badge-border-radius:4px;letter-spacing:.05em;background:var(--c);line-height:normal}
.file .pdf{--c:#dc2626}
.file .fig{--c:#9333ea}
.file .zip{--c:#0e7490}
.file .min-w-0{min-width:0}
.file .card-title{font-size:.9rem;font-weight:700;line-height:normal;margin-bottom:3px}
.file .card-text{font-size:.79rem;color:#667085}
.file .progress{--bs-progress-height:5px;--bs-progress-bg:#eef0f4;--bs-progress-bar-bg:#4f46e5;
  --bs-progress-border-radius:99px;margin-top:9px}
.file .progress-bar{border-radius:99px}
.file .done{color:#15803d;font-weight:600}
.file .fail{color:#b91c1c;font-weight:600}
.file .btn-icon{--bs-btn-padding-x:0;--bs-btn-padding-y:0;--bs-btn-border-width:0;--bs-btn-border-radius:8px;
  --bs-btn-color:#667085;--bs-btn-hover-color:#344054;--bs-btn-hover-bg:#f2f4f7;--bs-btn-active-color:#344054;
  --bs-btn-active-bg:#eaecf0;--bs-btn-focus-box-shadow:0 0 0 2px #4f46e5;width:30px;height:30px;display:grid;place-items:center}
.file .btn-icon svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2.1}
@media (prefers-reduced-motion:reduce){.file,.file .btn,.file .progress-bar{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<article class="flex w-[400px] max-w-full items-center gap-3.5 rounded-2xl border border-[#e9ecf1] bg-white px-4 py-3.5 transition-shadow duration-[180ms] hover:shadow-[0_10px_26px_-18px_rgba(16,24,40,.28)] motion-reduce:transition-none">
  <span class="relative grid h-[50px] w-[42px] shrink-0 [place-items:end_center] rounded-[7px] bg-[#f2f4f7] pb-[7px] after:absolute after:top-0 after:right-0 after:border-t-0 after:border-r-[12px] after:border-b-[12px] after:border-l-0 after:border-solid after:border-r-[#e4e7ec] after:border-b-white" aria-hidden="true"><b class="rounded bg-[#9333ea] px-1.5 py-0.5 text-[.6rem] font-extrabold tracking-[.05em] text-white">FIG</b></span>
  <div class="min-w-0 flex-1">
    <h2 class="mb-[3px] truncate text-[.9rem] font-bold">brand-system-v4.fig</h2>
    <p class="text-[.79rem] text-[#667085]">18.4 MB of 42.1 MB · 12 seconds left</p>
    <div class="mt-[9px] h-[5px] overflow-hidden rounded-full bg-[#eef0f4]" role="progressbar" aria-label="Uploading brand-system-v4.fig" aria-valuemin="0" aria-valuemax="100" aria-valuenow="44"><i class="block h-full w-[44%] rounded-full bg-[#4f46e5]"></i></div>
  </div>
  <div class="flex shrink-0 gap-[5px]"><button class="grid size-[30px] cursor-pointer place-items-center rounded-lg text-[#667085] hover:bg-[#f2f4f7] hover:text-[#344054] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[#4f46e5]" type="button" aria-label="Cancel upload of brand-system-v4.fig"><svg class="block size-[15px] fill-none stroke-current stroke-[2.1]" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button></div>
</article>

<article class="flex w-[400px] max-w-full items-center gap-3.5 rounded-2xl border border-[#e9ecf1] bg-white px-4 py-3.5 transition-shadow duration-[180ms] hover:shadow-[0_10px_26px_-18px_rgba(16,24,40,.28)] motion-reduce:transition-none">
  <span class="relative grid h-[50px] w-[42px] shrink-0 [place-items:end_center] rounded-[7px] bg-[#f2f4f7] pb-[7px] after:absolute after:top-0 after:right-0 after:border-t-0 after:border-r-[12px] after:border-b-[12px] after:border-l-0 after:border-solid after:border-r-[#e4e7ec] after:border-b-white" aria-hidden="true"><b class="rounded bg-[#dc2626] px-1.5 py-0.5 text-[.6rem] font-extrabold tracking-[.05em] text-white">PDF</b></span>
  <div class="min-w-0 flex-1">
    <h2 class="mb-[3px] truncate text-[.9rem] font-bold">2026-annual-report.pdf</h2>
    <p class="text-[.79rem] text-[#667085]"><span class="font-semibold text-[#15803d]">Uploaded</span> · 3.8 MB · 2 minutes ago</p>
  </div>
  <div class="flex shrink-0 gap-[5px]">
    <button class="grid size-[30px] cursor-pointer place-items-center rounded-lg text-[#667085] hover:bg-[#f2f4f7] hover:text-[#344054] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[#4f46e5]" type="button" aria-label="Download 2026-annual-report.pdf"><svg class="block size-[15px] fill-none stroke-current stroke-[2.1]" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4v11M7 11l5 5 5-5M5 20h14"/></svg></button>
    <button class="grid size-[30px] cursor-pointer place-items-center rounded-lg text-[#667085] hover:bg-[#f2f4f7] hover:text-[#344054] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[#4f46e5]" type="button" aria-label="Delete 2026-annual-report.pdf"><svg class="block size-[15px] fill-none stroke-current stroke-[2.1]" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 7h14M9 7V5h6v2M7 7l1 13h8l1-13"/></svg></button>
  </div>
</article>

<article class="flex w-[400px] max-w-full items-center gap-3.5 rounded-2xl border border-[#e9ecf1] bg-white px-4 py-3.5 transition-shadow duration-[180ms] hover:shadow-[0_10px_26px_-18px_rgba(16,24,40,.28)] motion-reduce:transition-none">
  <span class="relative grid h-[50px] w-[42px] shrink-0 [place-items:end_center] rounded-[7px] bg-[#f2f4f7] pb-[7px] after:absolute after:top-0 after:right-0 after:border-t-0 after:border-r-[12px] after:border-b-[12px] after:border-l-0 after:border-solid after:border-r-[#e4e7ec] after:border-b-white" aria-hidden="true"><b class="rounded bg-[#0e7490] px-1.5 py-0.5 text-[.6rem] font-extrabold tracking-[.05em] text-white">ZIP</b></span>
  <div class="min-w-0 flex-1">
    <h2 class="mb-[3px] truncate text-[.9rem] font-bold">site-backup-aug.zip</h2>
    <p class="text-[.79rem] text-[#667085]"><span class="font-semibold text-[#b91c1c]">Upload failed</span> · file exceeds the 100 MB limit</p>
  </div>
  <div class="flex shrink-0 gap-[5px]">
    <button class="grid size-[30px] cursor-pointer place-items-center rounded-lg text-[#667085] hover:bg-[#f2f4f7] hover:text-[#344054] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[#4f46e5]" type="button" aria-label="Retry upload of site-backup-aug.zip"><svg class="block size-[15px] fill-none stroke-current stroke-[2.1]" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 12a8 8 0 11-2.3-5.7"/><path d="M20 4v5h-5"/></svg></button>
    <button class="grid size-[30px] cursor-pointer place-items-center rounded-lg text-[#667085] hover:bg-[#f2f4f7] hover:text-[#344054] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[#4f46e5]" type="button" aria-label="Remove site-backup-aug.zip"><svg class="block size-[15px] fill-none stroke-current stroke-[2.1]" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
  </div>
</article>

About this set

Three compact file cards that cover the life of an upload: in progress, uploaded and failed. Each card shows a file-type badge drawn in CSS (a grey page with a folded corner and a coloured FIG, PDF or ZIP tag), the file name in a heading that truncates with an ellipsis, a status line and icon buttons on the right. The uploading card adds a thin progress bar with role=”progressbar” and its value in aria-valuenow, and offers Cancel. The uploaded card shows a green Uploaded label with Download and Delete, and the failed card shows a red Upload failed label with the reason, Retry and Remove. Use the set for upload queues, attachment lists and file managers; the three states share one layout, so a card can switch state without moving. Every icon button has a label that names the file, so a list of many files still reads clearly. The Bootstrap version uses .card, the stock .progress and .progress-bar, .badge and .btn restyled through their CSS variables; the Tailwind version is utilities only, including the folded corner.

What’s included

  • Uploading, uploaded and failed states in one layout
  • File-type badge with a folded corner drawn in CSS
  • Progress bar exposed as role="progressbar" with a value
  • Icon buttons labelled with the action and the file name
  • Long file names truncate with an ellipsis

Accessibility

File names are h2 headings, the progress bar has an accessible name and aria-valuenow, and the status text is written out as Uploaded or Upload failed rather than shown by colour alone. Each icon button has an aria-label such as Retry upload of site-backup-aug.zip, the icons and type badges are aria-hidden, and buttons show a 2px indigo focus ring. The hover shadow transition is switched off under reduced motion.

Customise it

The badge colour is --c on .pdf, .fig and .zip (plain CSS and Bootstrap) or the bg- class on each tag (Tailwind). The progress colour is #4f46e5 on .bar i, --bs-progress-bar-bg in Bootstrap, or the bar's bg- class in Tailwind; set its width and aria-valuenow together.