Skip to main content
The package ships the same compiled CSS in two files. Import exactly one of them, once. Neither installs a global reset. The component contract ships in the package as @gethinto/native-support-react/contract.json, with types at @gethinto/native-support-react/contract. It lists parts, states, required actions, and tokens. @gethinto/native-support-react/styles.layered.css puts every rule in the hinto cascade layer and starts with @layer base, hinto;. Your unlayered rules always beat Hinto’s, and rules in your base layer always lose to it. Rules in later layers beat Hinto’s only when your first @layer statement lists hinto before them. With that statement in place, the load order stops mattering, so you can import the file from JavaScript or CSS. Use it when your resets are layered or absent: Tailwind v4, or plain CSS without an unlayered reset. With Tailwind v4, put hinto in your first layer statement, after base and before components and utilities, so a utility you pass through className beats Hinto. If you declare your own layers, list hinto after your reset or base layers.
Use the unlayered @gethinto/native-support-react/styles.css when your host has an unlayered reset. Tailwind v3’s preflight is unlayered, and its [type='button'] rule has the same specificity as Hinto’s classes, so a layered Hinto loses its button backgrounds. The unlayered file’s rules have one class of specificity, so load it after your reset and before your overrides. With Tailwind v3, import from JavaScript in one module: your globals (with @tailwind base, @tailwind components, and @tailwind utilities), then @gethinto/native-support-react/styles.css, then your support overrides stylesheet. Do not use postcss-import to inline Hinto’s stylesheet; it does not rebase relative url() references, which breaks packages such as fontsource. A Tailwind utility that sets a property Hinto also sets needs the ! important modifier, or belongs in your overrides file. The token example assumes each host variable contains a complete color value, such as oklch(...). If your host stores HSL channels, wrap those variables with hsl(var(...)). Map surface and foreground together for contrast. Pass theme="light" or theme="dark" from your resolved host theme. If a Sheet portals outside your theme scope, put variables on its portal wrapper or on body. For a host input adapter, forward the actual textarea ref and all DOM props from Support.ComposerInput. A host button adapter must preserve Hinto’s type, disabled state, and click handler. Support.Messages owns the MessageScroller viewport and Jump to latest. Put the conversation inside your Sheet or Drawer. The former viewportRender prop was removed in contract version 2. Use jumpToLatest to customize the control, for example jumpToLatest={<Support.JumpToLatest className="my-jump">Newest</Support.JumpToLatest>}, and renderMessage to replace only the message body, rendering the text with <Support.MessageText message={message} />. Render bodies as text. Each text message has a Copy icon button with a tooltip beside its bubble. It takes no space in the row, so the time below the bubble stays aligned with it. It appears only when its bubble or the button is hovered (on touch screens, tapped), or when the message is focused from the keyboard. Restyle it with tokens or one class on .hinto-support__copy and .hinto-support__tooltip. You can also pass your own icon button to Support.Messages as copyRender={<Button variant="ghost" size="icon-sm" />}. A copyRender function must spread every prop it receives, including ref, onto a real button. Set copyTooltip={false} only when it renders its own tooltip from the label it receives. The composer is one box that is the input. Draft files sit on top, the textarea starts at one line and grows with the draft to min(40dvh, 12.5rem) before it scrolls, and the actions row holds an attach button on the left and a round send button on the right. To compose it yourself, put Support.ComposerAttachments, Support.ComposerInput, and Support.ComposerActions holding Support.Attach and Support.Send inside Support.Composer. Restyle the box with one class on .hinto-support__composer, change the growth cap with max-block-size on .hinto-support__input, and restyle the buttons with .hinto-support__attach and .hinto-support__send. The box uses the surface, border, and focus tokens; Send uses accent and on-accent, and disabled and on-disabled while there is nothing to send. Customers attach images (PNG, JPEG, GIF, WebP, and iPhone HEIC or HEIF photos, which Hinto stores as JPEG under a .jpg name), PDFs, and text files (plain text, CSV, JSON) up to 10 MB each and five per message, by the attach button, by pasting, or by dropping files on the box. Each file shows as a chip that is uploading, ready, or failed, with remove and, after a failed upload, retry. Send stays disabled until every file has uploaded. Sending empties the box at once: the message and its files show in the transcript as pending, and the customer can type the next message while it sends. A message that cannot be sent either stays in the transcript with Retry or returns to the box. To use your own buttons, pass them to Support.Attach and Support.Send as render={<Button />}; Hinto merges type, disabled, aria-label, onClick, and the icon. For your own file chips, pass renderAttachment={(file, { remove, retry }) => ...} to Support.ComposerAttachments; show file.filename and file.state, always offer remove, and offer retry when file.canRetry is true. A host input adapter owns its own height, and its domProps include onPaste, which attaches pasted files. The copy prop rewords any string. Hinto ships English only; to support another language, pass a complete SupportCopy object in that language, built from your own translations, and switch it with your app’s locale. Type it as SupportCopy, not Partial<SupportCopy>, so TypeScript reports any string you missed, including strings a later version adds. defaultCopy lists every key with its English text. Entries that take a file name, count, or ticket number are functions; use Intl.PluralRules for counts. Set dateFormat to the same locale so dates and times match.

Status and automatic reply

After a customer sends, Support.Messages shows your organization’s automatic reply, tagged as automatic, and a status row as the last row of the transcript: received, investigating, with a teammate, replied, resolved. The row expands into every step. Your team sets the reply text in Hinto under Settings > Auto-responses. The row is Support.Status. Pass status={null} to Support.Messages to hide it, or status={<YourStatus />} with a component that reads useSupportStatus() to draw it yourself. The unread count from useSupportEntry() never counts the automatic reply.

Help offer

Support.HelpOffer sits on your product page, outside the conversation, so tokens you set on the conversation’s class do not reach it. Set the --hinto-support-* tokens on :root, or on a class you pass as the slot’s className, and pass theme. Its strings are the helpOffer* copy keys. contactRender, retryRender, and dismissRender take your own buttons, render replaces the card while Hinto keeps the slot and its live region, and useHelpOffer(options) gives you the offer as data for a card you draw entirely. Journeys covers where to place it.

Parts and states

Every element Hinto renders has a data-hinto-part attribute, such as data-hinto-part="composer", and an element with states carries its current one in data-state. Target them with one attribute selector when a class is not enough. contract.json lists every part, state attribute, token, and render adapter. Pass initialFocus="none" to Support.Conversation to keep focus where it is when the conversation opens, instead of moving it to the composer.

Component props

Check your layout

Test 300 px and 375 px widths, a wide desktop layout, dark theme, keyboard focus, IME composition, and your actual Sheet.