Buttons
Every button in Hodi comes from one of these four components. A plugin that uses them therefore has buttons of the same height, the same colour and the same hover as the rest of the app, in all three themes.
Button
The button with a text, and if needed a Lucide icon before that text. It is 44 px tall, or 34 px with compact. On a screen, the main action's button takes the primary look, and a button that erases takes the danger look.
import { Button } from 'hodi:sdk'
import { Check } from 'lucide-react'
<Button
look="primary"
icon={Check}
onClick={save}
>
Save
</Button>childrenReactNodeThe button's text.
look?'neutral' | 'primary' | 'danger' | 'ai'The button's colour: neutral by default, primary for the main action, danger for erasing, ai for the AI.
icon?ComponentTypeA Lucide icon, shown at 16 px before the text.
busy?booleanThe button waits for the server: its icon becomes a spinning circle, and it can't be pressed.
compact?booleanThe button is 34 px tall, to fit in a row or a header.
wide?booleanThe button takes its parent's whole width.
href?stringMakes the button a link to this address. An address in Hodi comes from usePluginLinks().
external?booleanWith href: the link opens in a new tab.
…ButtonHTMLAttributesEverything a <button> accepts, such as onClick or disabled.
RoundButton
The round button, with a single icon and no text. Its label says what the button does: screen readers read it, and it shows on hover.
import { RoundButton } from 'hodi:sdk'
import { Pencil } from 'lucide-react'
<RoundButton
icon={Pencil}
label="Edit"
size={44}
onClick={edit}
/>iconLucideIconThe button's icon, a Lucide icon.
labelstringWhat the button does, for screen readers and on hover.
size?28 | 34 | 38 | 44The button's diameter, in px: 28 in a card, 34 in a header, 38 in a settings row on a phone, 44 for a button touched with a finger.
variant?'default' | 'on' | 'danger' | 'primary' | 'ai' | 'glass' | 'image'The button's colour. on shows it lit, like a chosen filter. glass and image are for a button laid over a photo.
filled?booleanFills the icon in, for example to show an article is saved.
busy?booleanMakes the icon spin, so it must be a loading icon.
href?stringMakes the button a link to this address.
external?booleanWith href: the link opens in a new tab.
AiButton
The purple button. It is the only way for a plugin to ask the household's AI a question. Each click runs the action of the same name in aiActions once, on the server side, and sends its answer to onAnswer.
Hodi hides this button for a teen, a child or a household without AI. It greys it out when the household has reached its limit for the day. The server context explains the server side.
import { AiButton } from 'hodi:sdk'
<AiButton
action="summary"
input={{ id: article.id }}
onAnswer={answer => setSummary(String(answer))}
>
Summarise
</AiButton>actionstringThe name of the action to run, as written in the server part's aiActions.
input?unknownThe value the action receives in request.input, 16 KB of JSON at most.
onAnswer(answer: unknown) => voidReceives what the action answered.
onError?(error: AiButtonError) => voidCalled when the question fails, instead of Hodi's error toast. The error is unavailable, off, limited, refused or failed.
childrenReactNodeThe button's text, a verb such as Summarise or Translate.
compact?booleanThe button is 34 px tall instead of 44.
wide?booleanThe button takes its parent's whole width.
disabled?booleanThe button is greyed out and can't be pressed.
ReaderButton
The small button that goes at the end of an article, next to Read the original. It is the button to use in the readerAction slot.
import { ReaderButton } from 'hodi:sdk'
import { Flag } from 'lucide-react'
<ReaderButton icon={<Flag size={12} />} onClick={report}>Report</ReaderButton>childrenReactNodeThe button's text.
onClick() => voidWhat a click on the button does.
icon?ReactNodeA 12 px Lucide icon, shown before the text.
done?booleanShows the action is already done for this article.
label?stringA fuller name than the text, for screen readers.