Mode
There are two modes, read for displaying the value, and edit for enabling control component.
Read mode
<State initial={'basic read example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
<InlineEdit
control={fieldProps => <Input small {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
/>
</BodyText>
</Card>
)}
</State>
Edit mode
In edit mode, control can be any component, recommended ones are shown in common examples.
<State initial={'Edit Example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
<InlineEdit
mode="edit"
control={fieldProps => <Input small {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
autoFocusControl={false}
/>
</BodyText>
</Card>
)}
</State>
Action
Action are default buttons shown in edit mode for save and cancel. It is displayed by default but it can also be hidden. The save and cancel function can be triggered using other components, checkout this example.
Layout
Inline (default)
Used when there is adjacent component that should be pushed when actions appear.
<State initial={'Inline'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
Hello this is
<InlineEdit
control={fieldProps => <Input small {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
actionLayout="inline"
/>
{` example.`}
</BodyText>
</Card>
)}
</State>
It can also be used with width="fluid"
to fill space.
<State initial={'Fluid width example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<InlineEdit
control={fieldProps => <Input small fluid {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
width="fluid"
/>
</Card>
)}
</State>
Floating
Applies popover to actions. Actions will be absolute positions.
<State initial={'Floating'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
Hello this is
<InlineEdit
control={fieldProps => <Input small {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
actionLayout="floating"
/>
{` example.`}
</BodyText>
</Card>
)}
</State>
None
Example below shows actionLayout='none'
with custom button inside control for saving.
For more specific use case checkout using custom read and edit component.
<State initial={'None'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
Hello this is
<InlineEdit
control={(fieldProps, actionProps) => (
<Input
small
placeholder="Enter"
action={<Button onClick={actionProps.save}>Save</Button>}
{...fieldProps}
/>
)}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
actionLayout="none"
/>
{` example.`}
</BodyText>
</Card>
)}
</State>
Direction
The placement of the save and cancel buttons can be controlled in the same way Popover directions are handled. The most common examples are right bottom and bottom left.
<Card>
<CardSection>
<Stack alignItems="space-between" justifyContent="center">
{['rb', 'bl'].map((item, index) => (
<StackItem key={index} style={{margin: 24, width: 'calc(33% - 48px)'}}>
<InlineEdit
mode="edit"
control={fieldProps => <TextArea style={{width: 150}} {...fieldProps} />}
value={item}
autoFocusControl={false}
actionDirection={item}
/>
</StackItem>
))}
</Stack>
</CardSection>
</Card>
Placeholder
In InlineEdit component, there is a default placeholder text is Enter value
. You can override this using placeholder
prop.
This placeholder is both used in the read component and the edit component.
<State initial={'placeholder example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
<InlineEdit
placeholder="Enter value"
control={fieldProps => <Input small {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
/>
</BodyText>
</Card>
)}
</State>
Decoration
<Card>
<Stack>
<StackItem fill style={{flexBasis: '100%'}}>
<BodyText el="span">
<InlineEdit
mode="read"
value="with decorations"
control={() => {}}
showContentOnEdit
actionLayout="none"
/>
</BodyText>
</StackItem>
<StackItem fill style={{flexBasis: '100%'}}>
<BodyText el="span">
<InlineEdit
mode="read"
value="no icon decoration"
decoration={{icon: false}}
control={() => {}}
showContentOnEdit
actionLayout="none"
/>
</BodyText>
</StackItem>
<StackItem fill style={{flexBasis: '100%'}}>
<BodyText el="span">
<InlineEdit
mode="read"
value="no icon, underline"
decoration={{icon: false, underline: false}}
control={() => {}}
showContentOnEdit
actionLayout="none"
/>
</BodyText>
</StackItem>
<StackItem fill style={{flexBasis: '100%'}}>
<BodyText el="span">
<InlineEdit
mode="read"
value="no icon, underline, color"
decoration={{icon: false, underline: false, color: false}}
control={() => {}}
showContentOnEdit
actionLayout="none"
/>
</BodyText>
</StackItem>
</Stack>
</Card>
Proximity, and Density
Decorations are used to draw attention to users for click action and when there are too many items fighting for attention, it becomes a distraction - when page has multiple Inline Edit components, be conservative of the decorations.
When the InlineEdit component is lower than tertiary action, do not use decorations.
Examples
Common
Using in Headline
<State initial={'Headline Example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<Headline el="span">
<InlineEdit
control={fieldProps => <Input placeholder="Enter" {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
decoration={{color: false, underline: false}}
value={submittedValue}
/>
</Headline>
</Card>
)}
</State>
<State initial={'Input Example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
<InlineEdit
control={fieldProps => <Input placeholder="Enter" {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
/>
</BodyText>
</Card>
)}
</State>
TextArea as control
<State initial={'TextArea Example'}>
{([submittedValue, setSubmittedValue]) => (
<Card>
<BodyText el="span">
<InlineEdit
control={fieldProps => <TextArea placeholder="Enter" {...fieldProps} />}
onSave={props => setSubmittedValue(props.value)}
value={submittedValue}
/>
</BodyText>
</Card>
)}
</State>
Select as control
const CommonSelect = () => {
const dummyOptions = [
{ text: 'Jane Doe', value: 1 },
{ text: 'Bob Ross', value: 2 },
{ text: 'Jackie Robinson', value: 3 },
{ text: 'Alexandria Garcia', value: 4 },
{ text: 'Zack Bower', value: 5 },
{ text: 'Erin Smith', value: 6 },
{ text: 'Jarrod Saltalamacchia', value: 7 },
{ text: 'Natalia McPhearson', value: 8 }
];
const value = dummyOptions[0];
const [submittedValue, setSubmittedValue] = React.useState(value);
const onSave = props => setSubmittedValue(props.value);
const getControl = fieldProps => (
<AnvilSelect
trigger={{
size: 'small',
}}
options={dummyOptions}
{...fieldProps}
/>
);
return (
<Card>
<BodyText el="span">
<InlineEdit
control={getControl}
onSave={onSave}
value={submittedValue}
/>
</BodyText>
</Card>
);
};
render (<CommonSelect />);
Select multiple as control
const CommonSelectMultiple = () => {
const dummyOptions = [
{ text: 'Jane Doe', value: 1 },
{ text: 'Bob Ross', value: 2 },
{ text: 'Jackie Robinson', value: 3 },
{ text: 'Alexandria Garcia', value: 4 },
{ text: 'Zack Bower', value: 5 },
{ text: 'Erin Smith', value: 6 },
{ text: 'Jarrod Saltalamacchia', value: 7 },
{ text: 'Natalia McPhearson', value: 8 }
];
const value = [dummyOptions[0], dummyOptions[3], dummyOptions[4], dummyOptions[6]];
const [submittedValue, setSubmittedValue] = React.useState(value);
const onSave = props => setSubmittedValue(props.value);
const getControl = fieldProps => (
<AnvilSelect
multiple
trigger={{
size: 'small',
}}
options={dummyOptions}
{...fieldProps}
/>
);
return (
<Card>
<BodyText el="span">
<InlineEdit
control={getControl}
onSave={onSave}
value={submittedValue}
decoration={{underline: false}}
/>
</BodyText>
</Card>
);
};
render (<CommonSelectMultiple />);
Custom
You can add custom content and complex control for the InlineEdit.
Using custom read component
const OverridingContent = () => {
const value = 'Custom Read mode';
const [submittedValue, setSubmittedValue] = React.useState(value);
const onSave = props => setSubmittedValue(props.value);
const getControl = fieldProps => <Input placeholder="Enter" {...fieldProps} />;
const getContent = () => <TagGroup><Tag>{submittedValue}</Tag></TagGroup>;
return (
<Card>
<BodyText el="span">
<InlineEdit
control={getControl}
onSave={onSave}
value={submittedValue}
content={getContent}
/>
</BodyText>
</Card>
);
};
render (<OverridingContent />)
Using custom read and edit component
const CustomModalExample = () => {
const [savedValue, setSavedValue] = React.useState(['Bob']);
const [value, setValue] = React.useState(savedValue);
const [open, setOpen] = React.useState(false);
const handleSave = () => {
setSavedValue(value);
setOpen(false);
};
const handleOnChange = (value, checked) => {
if(checked){
setValue(prevState => [...prevState, value])
} else {
setValue(prevState => [...prevState].filter(item => item !== value))
}
};
const handleOnClick = () => {
setOpen(true);
};
const handleCancel = () => {
setValue(savedValue);
setOpen(false);
};
const getContent = () => {
return (
<TagGroup>
{savedValue.map((item, i) => {
return (
<Tag key={i}>{item}</Tag>
);
})}
</TagGroup>
);
};
const getControl = () => {
return (
<Modal
open={open}
closable
onClose={handleCancel}
title="Test Input in Modal"
footer={(
<ButtonGroup>
<Button onClick={handleCancel}>Cancel</Button>
<Button onClick={handleSave} primary>Save</Button>
</ButtonGroup>
)}
>
<Form>
<Form.Checkbox onChange={handleOnChange} label="Bob" value="Bob" checked={value.includes('Bob')}/>
<Form.Checkbox onChange={handleOnChange} label="Jane" value="Jane" checked={value.includes('Jane')}/>
</Form>
</Modal>
);
};
return (
<Card>
<InlineEdit
mode={open ? 'edit' : 'read'}
control={getControl}
onClick={handleOnClick}
actionLayout="none"
content={getContent}
showContentOnEdit
/>
</Card>
);
};
render (CustomModalExample)
Best Practices
- Use to update a single pre-existing data.
- When editing content is a primary task, use form instead.
- Do not use InlineEdit and other form controls in the same form.