EncryptedUpload
EncryptedUpload is a composite component that groups an encryption toggle button with a file input and an upload action button.
It composes InputGroup, Button, FileInputField, and ButtonAction into a cohesive unit with optional Popover support for enforced encryption scenarios.
Basic Usage
To implement the EncryptedUpload component, import it first:
import {
ButtonAction,
EncryptedUpload,
} from 'rades_react';
Then use it with a controlled encrypted state and an onFileChange handler:
React.createElement(() => {
const [encrypted, setEncrypted] = React.useState(false);
return (
<EncryptedUpload
encrypted={encrypted}
label="Attachment"
onEncryptedChange={setEncrypted}
onFileChange={(files) => console.log('Selected files:', files)}
>
<ButtonAction
color="secondary"
label="Upload"
onClick={() => Promise.resolve(true)}
/>
</EncryptedUpload>
);
})
Locked Encryption
Set locked to true to prevent the user from changing the encryption state.
When locked is set, clicking the toggle suppresses onEncryptedChange.
Provide lockedDescription to show a Popover with an
explanation when the toggle is clicked.
Locked: Encrypted
Set encrypted to true and locked to true. Provide a lockedDescription
to explain why encryption cannot be disabled.
React.createElement(() => {
// DO NOT COPY the wrapping <div> into your code. It's only needed for this
// preview to provide space for the popover with the description.
return (
<div style={{ display: 'grid', placeContent: 'start center', height: '12rem' }}>
<EncryptedUpload
encrypted
label="Attachment"
locked
lockedDescription="Encryption is enforced by your organization's security policy and cannot be disabled."
onFileChange={(files) => console.log('Selected files:', files)}
>
<ButtonAction
color="secondary"
label="Upload"
onClick={() => Promise.resolve(true)}
/>
</EncryptedUpload>
</div>
);
})
Locked: Unencrypted
Set encrypted to false and locked to true. Provide a lockedDescription
to explain why encryption is not available.
React.createElement(() => {
// DO NOT COPY the wrapping <div> into your code. It's only needed for this
// preview to provide space for the popover with the description.
return (
<div style={{ display: 'grid', placeContent: 'start center', height: '12rem' }}>
<EncryptedUpload
encrypted={false}
label="Attachment"
locked
lockedDescription="Encryption is not available on this device."
onFileChange={(files) => console.log('Selected files:', files)}
>
<ButtonAction
color="secondary"
label="Upload"
onClick={() => Promise.resolve(true)}
/>
</EncryptedUpload>
</div>
);
})
Without Action Button
The action button can be omitted when the upload is triggered externally, for example by a form submit button.
React.createElement(() => {
const [encrypted, setEncrypted] = React.useState(false);
return (
<EncryptedUpload
encrypted={encrypted}
label="Attachment"
onEncryptedChange={setEncrypted}
onFileChange={() => {}}
/>
);
})
Sizes
Three sizes are available: small, medium, and large.
React.createElement(() => {
const [encryptedSmall, setEncryptedSmall] = React.useState(false);
const [encryptedMedium, setEncryptedMedium] = React.useState(false);
const [encryptedLarge, setEncryptedLarge] = React.useState(false);
return (
<>
<EncryptedUpload
encrypted={encryptedSmall}
label="Attachment"
onEncryptedChange={setEncryptedSmall}
onFileChange={() => {}}
size="small"
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
<EncryptedUpload
encrypted={encryptedMedium}
label="Attachment"
onEncryptedChange={setEncryptedMedium}
onFileChange={() => {}}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
<EncryptedUpload
encrypted={encryptedLarge}
label="Attachment"
onEncryptedChange={setEncryptedLarge}
onFileChange={() => {}}
size="large"
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
</>
);
})
Invisible Label
In some cases, it may be convenient to visually hide the group label. The label remains accessible to assistive technologies.
While it may be acceptable for simple forms with just a few fields, it's dangerous to hide labels from users in most cases. Keep in mind you should provide another visual clue so users know what to fill into the input.
React.createElement(() => {
const [encrypted, setEncrypted] = React.useState(false);
return (
<EncryptedUpload
encrypted={encrypted}
isLabelVisible={false}
label="Attachment"
onEncryptedChange={setEncrypted}
onFileChange={() => {}}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
);
})
Horizontal Layout
The default vertical layout is straightforward to use and work with. However, there are situations where horizontal layout suits better — and that's why React UI supports this kind of layout as well.
React.createElement(() => {
const [encrypted, setEncrypted] = React.useState(false);
return (
<EncryptedUpload
encrypted={encrypted}
label="Attachment"
layout="horizontal"
onEncryptedChange={setEncrypted}
onFileChange={() => {}}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
);
})
Help Text
You may provide one or more additional help texts to clarify the upload field.
React.createElement(() => {
const [encrypted, setEncrypted] = React.useState(false);
return (
<EncryptedUpload
encrypted={encrypted}
helpTexts={[
'Select a file to upload. Maximum file size: 10 MB.',
]}
label="Attachment"
onEncryptedChange={setEncrypted}
onFileChange={() => {}}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
);
})
States
Disabled State
<EncryptedUpload
disabled
encrypted={false}
label="Attachment"
onFileChange={() => {}}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
Validation States
Validation states visually present the result of validation of the upload field. You should always provide a validation message for states other than valid so users know what happened and what action they should take or what options they have.
React.createElement(() => {
const [encryptedValid, setEncryptedValid] = React.useState(false);
const [encryptedInvalid, setEncryptedInvalid] = React.useState(false);
const [encryptedWarning, setEncryptedWarning] = React.useState(false);
return (
<>
<EncryptedUpload
encrypted={encryptedValid}
label="Attachment"
onEncryptedChange={setEncryptedValid}
onFileChange={() => {}}
validationState="valid"
validationTexts={['File is ready to upload.']}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
<EncryptedUpload
encrypted={encryptedInvalid}
label="Attachment"
onEncryptedChange={setEncryptedInvalid}
onFileChange={() => {}}
validationState="invalid"
validationTexts={['File is too large. Please select a file smaller than 10 MB.']}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
<EncryptedUpload
encrypted={encryptedWarning}
label="Attachment"
onEncryptedChange={setEncryptedWarning}
onFileChange={() => {}}
validationState="warning"
validationTexts={['This file type may not be supported by all recipients.']}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
</>
);
})
Ref Forwarding
A ref passed to EncryptedUpload is forwarded to the inner FileInputField,
giving access to its instance methods such as resetState.
React.createElement(() => {
const ref = React.useRef();
const [encrypted, setEncrypted] = React.useState(false);
return (
<>
<EncryptedUpload
encrypted={encrypted}
label="Attachment"
onEncryptedChange={setEncrypted}
onFileChange={() => {}}
ref={ref}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
<div>
<Button
color="danger"
label="Reset file input state"
onClick={() => {
if (!ref.current) {
return;
}
ref.current.resetState();
}}
/>
</div>
</>
);
})
To disable the upload button until a file is selected, track file selection
with onFileChange and derive a hasFile state from it. Pass
disabled={!hasFile} to ButtonAction so it stays inactive until the user
picks a file. After a successful upload, call ref.current.resetState() to
clear the file input and reset hasFile to false.
React.createElement(() => {
const ref = React.useRef();
const [encrypted, setEncrypted] = React.useState(false);
const [hasFile, setHasFile] = React.useState(false);
return (
<>
<EncryptedUpload
encrypted={encrypted}
label="Attachment"
onEncryptedChange={setEncrypted}
onFileChange={(files) => setHasFile(files.length > 0)}
ref={ref}
>
<ButtonAction
color="secondary"
disabled={!hasFile}
label="Upload"
onClick={() => {
return Promise.resolve(true).then((success) => {
if (success) {
ref.current?.resetState();
setHasFile(false);
}
return success;
});
}}
/>
</EncryptedUpload>
</>
);
})
Forwarding HTML Attributes
In addition to the options below in the component's API section, you
can specify any HTML attribute you like. All attributes that don't
interfere with the API are forwarded to the <input type="file"> HTML
element. This enables customizing the file input, for example restricting
accepted file types or allowing multiple files.
React.createElement(() => {
const [encrypted, setEncrypted] = React.useState(false);
return (
<EncryptedUpload
accept="image/*"
encrypted={encrypted}
label="Profile picture"
multiple
onEncryptedChange={setEncrypted}
onFileChange={() => {}}
>
<ButtonAction color="secondary" label="Upload" onClick={() => Promise.resolve(true)} />
</EncryptedUpload>
);
})
👉 Refer to the MDN reference for the full list of supported attributes of the input element.