upload area
An upload area is an alternative for the input file upload button. The upload area let the user choose one or more files from their device storage - either via the browse link (that works similar to the input file upload), or via drag and drop into the upload area. These selected files can be uploaded to a server through form submission or be manipulated using the Javascript File API.
The variant Upload area with items shows all states, a file item can have: upload
, uploading
, uploaded
and error
.
When selecting / drag and drop files, a custom event called filesAdded
is dispatched to the input element.
To handle the files, you have to add an event listener to the input element for the event filesAdded
.
The demonstrator Upload area demonstrator with custom event example is showing an example and logs the added files to the console.
component variations
default
<div class="m-upload-area">
<div class="m-upload-area__field">
<div class="m-upload-area__description">
<i class="a-icon boschicon-bosch-ic-upload"></i>
Drag and drop files here or
<input
id="upload-input-1"
class="m-upload-area__input"
name="upload-input"
type="file"
multiple=""
/>
<label for="upload-input-1">browse</label>
to upload.
</div>
</div>
<div class="m-upload-area__items"></div>
</div>
Upload area with global error
<div class="m-upload-area">
<div class="m-upload-area__field">
<div class="m-upload-area__description">
<i class="a-icon boschicon-bosch-ic-upload"></i>
Drag and drop files here or
<input
id="upload-input-2"
class="m-upload-area__input"
name="upload-input"
type="file"
multiple=""
/>
<label for="upload-input-2">browse</label>
to upload.
</div>
</div>
<div class="a-notification a-notification--text -error" role="alert">
<i class="a-icon ui-ic-alert-error"></i>
<div id="notification-label-id-text-error" class="a-notification__content">
This is an optional global upload error notification.
</div>
</div>
<div class="m-upload-area__items"></div>
</div>
Upload area with items
32.4 MB
16.8 MB
13.1 MB
3.6 MB
<div class="m-upload-area">
<div class="m-upload-area__field">
<div class="m-upload-area__description">
<i class="a-icon boschicon-bosch-ic-upload"></i>
Drag and drop files here or
<input
id="upload-input-3"
class="m-upload-area__input"
name="upload-input"
type="file"
multiple=""
/>
<label for="upload-input-3">browse</label>
to upload.
</div>
</div>
<div class="m-upload-area__items">
<div class="m-upload-area__item">
<div class="m-upload-area__item-details">
<div class="m-upload-area__item-description">
<i class="a-icon boschicon-bosch-ic-document-plain"></i>
<div>
<strong class="-size-m">ready-to-upload-file.jpg</strong>
<br />
<span class="-size-s">32.4 MB</span>
</div>
</div>
<div class="m-upload-area__item-cta">
<button type="button" class="a-button a-button--integrated">
<i class="a-icon a-button__icon boschicon-bosch-ic-upload"></i>
<span class="a-button__label">Upload</span>
</button>
<button
type="button"
class="a-button a-button--integrated -without-label"
aria-label="delete"
>
<i class="a-icon a-button__icon boschicon-bosch-ic-delete"></i>
</button>
</div>
</div>
</div>
<div class="m-upload-area__item">
<div class="m-upload-area__item-details">
<div class="m-upload-area__item-description">
<i class="a-icon boschicon-bosch-ic-document-plain"></i>
<div>
<strong class="-size-m">uploading-file.jpg</strong>
<br />
<span class="-size-s">16.8 MB</span>
</div>
</div>
<div class="m-upload-area__item-cta">
<button
type="button"
class="a-button a-button--integrated -without-label"
aria-label="delete"
>
<i class="a-icon a-button__icon boschicon-bosch-ic-delete"></i>
</button>
</div>
</div>
<div class="m-upload-area__progress">
<div class="a-progress-indicator-container">
<progress
class="a-progress-indicator -determinate"
value="25"
max="100"
></progress>
<div class="a-progress-indicator__inner-bar"></div>
</div>
<div class="-size-s m-upload-area__progress-percentage">25%</div>
</div>
</div>
<div class="m-upload-area__item">
<div class="m-upload-area__item-details">
<div class="m-upload-area__item-description">
<i class="a-icon boschicon-bosch-ic-document-plain"></i>
<div>
<strong class="-size-m">uploaded-file.jpg</strong>
<br />
<span class="-size-s">13.1 MB</span>
</div>
</div>
<div class="m-upload-area__item-cta">
<button
type="button"
class="a-button a-button--integrated -without-label"
aria-label="delete"
>
<i class="a-icon a-button__icon boschicon-bosch-ic-delete"></i>
</button>
</div>
</div>
</div>
<div class="m-upload-area__item">
<div class="m-upload-area__item-details">
<div class="m-upload-area__item-description">
<i class="a-icon boschicon-bosch-ic-document-plain"></i>
<div>
<strong class="-size-m">upload-failed-file.jpg</strong>
<br />
<span class="-size-s">3.6 MB</span>
</div>
</div>
<div class="m-upload-area__item-cta">
<button type="button" class="a-button a-button--integrated">
<i class="a-icon a-button__icon boschicon-bosch-ic-reset"></i>
<span class="a-button__label">Try again</span>
</button>
<button
type="button"
class="a-button a-button--integrated -without-label"
aria-label="delete"
>
<i class="a-icon a-button__icon boschicon-bosch-ic-delete"></i>
</button>
</div>
</div>
<div class="a-notification a-notification--text -error" role="alert">
<i class="a-icon ui-ic-alert-error"></i>
<div
id="notification-label-id-text-error"
class="a-notification__content"
>
File failed to load. Please try again!
</div>
</div>
</div>
<div class="m-upload-area__cta">
<button type="button" class="a-button a-button--secondary">
<i class="a-icon a-button__icon boschicon-bosch-ic-upload"></i>
<span class="a-button__label">Upload all</span>
</button>
<button type="button" class="a-button a-button--tertiary">
<i class="a-icon a-button__icon boschicon-bosch-ic-delete"></i>
<span class="a-button__label">Remove all</span>
</button>
</div>
</div>
</div>
Upload area demonstrator with custom event example
<script>
window.addEventListener("load", (event) => {
const uploadInput = document.getElementById('upload-input-4');
uploadInput.addEventListener('filesAdded', (e) => {
console.log('files added', e.detail.files);
});
});
</script>
<div class="m-upload-area">
<div class="m-upload-area__field">
<div class="m-upload-area__description">
<i class="a-icon boschicon-bosch-ic-upload"></i>
Drag and drop files here or
<input
id="upload-input-4"
class="m-upload-area__input"
name="upload-input"
type="file"
multiple=""
/>
<label for="upload-input-4">browse</label>
to upload.
</div>
</div>
<div class="m-upload-area__items"></div>
</div>
additional content
styles SCSS
.m-upload-area {
color: var(--plain__enabled__front__default);
&__field {
height: 240px;
background-color: var(--neutral__enabled__fill__default);
background-image: linear-gradient(to right, var(--neutral__enabled__front__default) 50%, transparent 50%), linear-gradient(to right, var(--neutral__enabled__front__default) 50%, transparent 50%), linear-gradient(to bottom, var(--neutral__enabled__front__default) 50%, transparent 50%), linear-gradient(to bottom, var(--neutral__enabled__front__default) 50%, transparent 50%);
background-position: left top, left bottom, left top, right top;
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
background-size: 2rem 1px, 2rem 1px, 1px 2rem, 1px 2rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
+ .a-notification {
padding-block: .75rem;
}
}
&__description {
max-width: 200px;
text-align: center;
.a-icon {
display: block;
font-size: 3rem;
margin-bottom: 0.5rem;
}
label {
cursor: pointer;
text-decoration: underline;
font-size: 1rem;
}
}
&__input {
width: 0;
height: 0;
opacity: 0;
&:focus-visible {
& + label {
@include focus-outside;
&::after {
outline-color: var(--neutral__enabled__fill__default);
}
}
}
}
&__items {
margin-top: 1rem;
}
&__item {
border-top: 1px solid var(--small__enabled__fill__default);
padding-block: 1rem;
&:first-child {
border-top: none;
}
}
&__item-details {
display: flex;
justify-content: space-between;
+ .a-notification {
margin-top: .25rem;
}
}
&__item-description {
display: flex;
flex-grow: 1;
align-items: center;
gap: 1rem;
.a-icon {
margin: .75rem;
}
}
&__item-cta {
display: flex;
justify-content: flex-end;
align-items: center;
}
&__progress {
display: flex;
align-items: center;
.a-progress-indicator-container {
flex-grow: 1;
}
}
&__progress-percentage {
width: 3rem;
text-align: center;
}
&__cta {
margin-top: 1rem;
display: flex;
justify-content: flex-end;
gap: .75rem;
}
}