flowiseai/flowise
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 25, 2026
Elevated
Design risk in this codebase.
More findings
Verdict
Assistant cards look like a marketplace but behave like a slideshow: unreachable by keyboard, mute icons, and a blank screen while data loads. One bad record can blank the whole grid, showing the UI wasn't stress-tested against real-world API responses.
Files Rams reviewed
packages/ui/src/views/assistants/custom/CustomAssistantLayout.jsx
packages/ui/src/views/assistants/openai/OpenAIAssistantLayout.jsx
packages/ui/src/views/assistants/index.jsx
packages/ui/src/views/chatbot/index.jsx
packages/ui/src/views/chatflows/index.jsx
packages/ui/src/views/files/index.jsx
packages/ui/src/views/serverlogs/index.jsx
packages/ui/src/views/settings/index.jsx
packages/agentflow/src/features/canvas/components/AgentflowHeader.tsx
packages/agentflow/src/features/canvas/components/ConnectionLine.tsx
packages/agentflow/src/features/canvas/components/NodeIcon.tsx
packages/agentflow/src/features/canvas/components/NodeInputHandle.tsx
packages/agentflow/src/features/canvas/components/NodeModelConfigs.tsx
packages/agentflow/src/features/canvas/components/NodeOutputHandles.tsx
packages/agentflow/src/features/canvas/components/NodeStatusIndicator.tsx
packages/agentflow/src/features/canvas/components/NodeToolIcons.tsx
packages/agentflow/src/features/canvas/components/NodeToolbarActions.tsx
packages/agentflow/src/features/canvas/components/ValidationFeedback.tsx
packages/observe/src/features/executions/components/ChatMessageBubble.tsx
packages/observe/src/features/executions/components/ExecutionDetail.tsx
packages/observe/src/features/executions/components/ExecutionTreeSidebar.tsx
packages/observe/src/features/executions/components/ExecutionsListTable.tsx
packages/observe/src/features/executions/components/ExecutionsViewer.tsx
packages/observe/src/features/executions/components/FulfilledConditionsBlock.tsx
packages/observe/src/features/executions/components/HitlPanel.tsx
packages/observe/src/features/executions/components/NodeContentRenderer.tsx
packages/observe/src/features/executions/components/NodeExecutionDetail.tsx
packages/observe/src/features/executions/components/RawJsonPanel.tsx
packages/observe/src/features/executions/components/ToolAccordionList.tsx
packages/observe/src/features/executions/components/UsedToolChips.tsx
Accessibility
packages/ui/src/views/assistants/index.jsx:87
Assistant selection cards are unreachable by keyboard
The StyledCard elements for 'Custom Assistant' and 'OpenAI Assistant' navigate on onClick={() => onCardClick(index)} but render as a plain MUI Card (a div) with no role, tabIndex, or onKeyDown handler.
Why it matters
A keyboard-only or screen-reader user tabbing through this page has no way to focus or activate either card, so they cannot reach the custom or OpenAI assistant flows at all.
Fix
Give click-driven navigation cards a real interactive role: add role='button', tabIndex={0}, and an onKeyDown handler that fires the same navigation on Enter/Space.
<StyledCard
key={index}
gradient={card.gradient}
sx={{ ... }}
onClick={() => onCardClick(index)}
><StyledCard
key={index}
gradient={card.gradient}
sx={{ ... }}
role='button'
tabIndex={0}
onClick={() => onCardClick(index)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') onCardClick(index)
}}
>packages/ui/src/views/chatflows/index.jsx:161
Card/list view toggle icons have no accessible name
The ToggleButton controls for card and list view (value='card', containing only <IconLayoutGrid />) rely on the title attribute for a label with no aria-label on the button itself.
Why it matters
The title attribute only produces a mouse hover tooltip and is not reliably exposed as an accessible name by screen readers, so a screen reader user hears an unlabeled toggle button when switching between card and list views.
Fix
Give icon-only interactive controls an explicit aria-label matching their visible purpose.
<ToggleButton
sx={{ ... }}
variant='contained'
value='card'
title='Card View'
>
<IconLayoutGrid />
</ToggleButton><ToggleButton
sx={{ ... }}
variant='contained'
value='card'
title='Card View'
aria-label='Card View'
>
<IconLayoutGrid />
</ToggleButton>packages/ui/src/views/assistants/custom/CustomAssistantLayout.jsx:144
Empty state illustration alt text is a filename, not a description
The empty-state image uses alt='AssistantEmptySVG', which is the imported asset's variable name rather than a description of the image content.
Why it matters
Screen reader users hear the literal string 'AssistantEmptySVG' announced, which conveys nothing about the empty state and adds confusing noise instead of context.
Fix
Use alt text that describes the image's meaning, or mark purely decorative images with alt='' so they are skipped by assistive tech.
<img
style={{ objectFit: 'cover', height: '20vh', width: 'auto' }}
src={AssistantEmptySVG}
alt='AssistantEmptySVG'
/><img
style={{ objectFit: 'cover', height: '20vh', width: 'auto' }}
src={AssistantEmptySVG}
alt=''
role='presentation'
/>UX
packages/ui/src/views/chatbot/index.jsx:99
Invalid chatbot error state offers no way to recover
The 'Invalid Chatbot' Card shows an IconCircleXFilled icon, the heading 'Invalid Chatbot', and body text explaining the chatbot doesn't exist or needs API key auth, but includes no link or button to go anywhere else.
Why it matters
A user who followed a broken or expired chatbot link hits a dead end with no way to retry, search, or return to a working page, which is the worst place to leave someone stuck.
Fix
Give every terminal error state a recovery action, such as a home link or retry button, alongside the explanation.
<Typography variant='body1' color='text.secondary' align='center'>
{`The chatbot you're looking for doesn't exist or requires API key authentication.`}
</Typography>
</Stack> <Typography variant='body1' color='text.secondary' align='center'>
{`The chatbot you're looking for doesn't exist or requires API key authentication.`}
</Typography>
<Button variant='outlined' href='/'>Go to Home</Button>
</Stack>packages/ui/src/views/chatbot/index.jsx:113
Chatbot page renders a blank screen while loading
The component's return statement is {!isLoading ? (<>...</>) : null}, so while isLoading is true nothing at all is rendered, not even a spinner or skeleton.
Why it matters
Users opening a shared chatbot link see a blank white page during the load window with no feedback that anything is happening, which reads as broken rather than loading.
Fix
Render a loading indicator in the null branch instead of nothing, so the interface always gives visible feedback during async waits.
) : null}
</>
)
} ) : (
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '80vh' }}>
<CircularProgress />
</Box>
)}
</>
)
}Get this score on every PR.
Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.
Install Rams freeCraft
packages/ui/src/views/assistants/openai/OpenAIAssistantLayout.jsx:91
One malformed assistant record blanks the entire grid
filterAssistants calls JSON.parse(data.details) directly with no try/catch, and it runs on every item in getAllAssistantsApi.data.filter(filterAssistants) during render.
Why it matters
If a single assistant record has invalid JSON in its details field, the parse throws, the filter call fails, and the whole assistants grid crashes instead of showing the other valid assistants.
Fix
Wrap JSON.parse in a try/catch inside data-derived filter and map functions so one bad record degrades gracefully instead of crashing the view.
function filterAssistants(data) {
const parsedData = JSON.parse(data.details)
return parsedData && parsedData.name && parsedData.name.toLowerCase().indexOf(search.toLowerCase()) > -1
}function filterAssistants(data) {
try {
const parsedData = JSON.parse(data.details)
return parsedData && parsedData.name && parsedData.name.toLowerCase().indexOf(search.toLowerCase()) > -1
} catch (e) {
return false
}
}Typography
Color
Spacing
Components
Motion
Working well
- The 'Load' (outlined) and 'Add' (contained) buttons in the header are correctly differentiated by fill weight, making the primary creation action visually stronger.
- Separating card view and table view (FlowListTable) behind a persisted ToggleButtonGroup choice respects returning users' preferred density via localStorage.
- The error card correctly derives its border and shadow color from theme.palette.error.main via alpha(), keeping it themeable instead of a hardcoded hex.
- The Chip labeled 'Deprecating' pairs a warning color with a visible text label, so the deprecation state isn't conveyed by color alone.
Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 9, 2026: 59/100. This rescore on v0.0.3: 59/100.
This page is an automated design review of flowiseai/flowise’s UI code: 30 files read against 309 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
More design scores
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.