Customizing look and feel

Match the tax documentation form to your product's design.

The SDK ships a default stylesheet so your first render isn't broken, but it's a starting point rather than a design system you're expected to keep. Every element carries a namespaced taxbit- class, and those class names are a stable contract — restyle what you need or replace the styling outright. This page covers what you can change, the class names to target, and how far you can take it.

For the rest of the integration flow, see the Questionnaire integration guide.

Style it with your AI coding agent

Taxbit publishes an agent skill that teaches Claude Code, Cursor, GitHub Copilot, Windsurf, and 40+ other agents how the form is built — every class name, the override patterns, and the gotchas. It's the fastest path from the default styling to your brand.

npx skills add taxbit-shared/taxbit-skills

Then prompt your agent inside your own codebase:

Style the Taxbit tax documentation form to match our design system. Our design
tokens are in <path/to/tokens> and our components are in <path/to/components>.
Write the overrides to src/styles/taxbit-overrides.css and import it after the
Taxbit base stylesheet. Match our colors, typography, border radius, spacing,
and input and button styles.

Point the agent at your existing tokens and components. That's what makes the output match your product rather than approximate it. The rest of this page documents what the agent works from, so you can review and extend its work.

Claude Code users can install it as a plugin instead, which also adds the /taxbit:react-sdk command:

/plugin marketplace add https://github.com/taxbit-shared/taxbit-skills.git

What you can change

You controlTaxbit controls
Colors, fonts, and text sizesWhich questions appear
Spacing, borders, and radiusThe order they appear in
Button and input stylesHow each question is worded
Form widthWhich answers are valid
Whether labels sit above or beside inputsWhich form type applies (W-9, W-8BEN-E, MRDP, CRS, CARF)

Presentation is yours. Question content and sequence are driven by tax regulation and the form type, so they aren't styling options — changing them would put your filings at risk. In practice you can make the form look native to your product, but you can't reorder or reword the questions.

How styling works

TaxbitQuestionnaire and TaxbitCuringDocumentation render the same class names, so one stylesheet covers both.

  • It's ordinary CSS. Write rules against the taxbit- class names the same way you style any other part of your app.
  • Every class is namespaced. The taxbit- prefix keeps SDK styles from colliding with yours.
  • Your brand values live wherever you want them. Declare your own CSS variables at the top of your stylesheet and reuse them throughout — see Set your brand basics.
  • Import your stylesheet after the SDK's. Whichever comes last wins.
import '@taxbit/react-sdk/style/inline.css'; // optional starting point — at most one
import './taxbit-overrides.css';             // yours, always imported after

Styling escalates through five stages, and each is a reasonable place to stop. Most integrations stop after the second.

Choose a starting point

Import at most one base stylesheet. Importing none is a normal choice.

ImportLabel positionWhat you get
(none)your choiceNo SDK styling. You write every rule. Cleanest slate, most work.
style/minimal.cssyour choiceStructure only — form width, field spacing, status colors. Best starting point if you intend to restyle.
style/inline.cssbeside the inputThe default look — layout, inputs, buttons, badges. Use when the default is close and you only need to tweak.
style/basic.cssabove the inputSame as inline.css, with each label on its own line above the field.

The meaningful difference between inline.css and basic.css is label placement. .taxbit-row uses flex-direction: row in one and column in the other. Pick whichever matches the forms elsewhere in your product. They also differ slightly in radio-option spacing and one postal-code margin.

style/index.css is a demo-app stylesheet. It sets fonts, text color, and padding on :root and html, so it restyles your entire page rather than the form. Don't import it in production.

Set your brand basics

These rules cover most of what makes the form read as someone else's. Declare your own CSS variables at the top of the file so brand values live in one place:

/* taxbit-overrides.css — imported after the base stylesheet */

.taxbit-page {
  --brand-primary: #6b21a8;
  --brand-primary-hover: #581c87;
  --brand-text: #1f2937;
  --brand-border: #d1d5db;
  --brand-radius: 6px;
  --brand-font: 'Inter var', system-ui, sans-serif;

  font-family: var(--brand-font);
  color: var(--brand-text);
  max-width: 820px;
}

/* Primary action — Next and Submit */
.taxbit-step-actions .taxbit-primary-actions > button {
  background-color: var(--brand-primary);
  border-color: var(--brand-primary);
  color: #fff;
}
.taxbit-step-actions .taxbit-primary-actions > button:hover {
  background-color: var(--brand-primary-hover);
  border-color: var(--brand-primary-hover);
}

/* Secondary action — Back and Cancel */
.taxbit-step-actions .taxbit-secondary-actions > button {
  background-color: transparent;
  border-color: var(--brand-border);
  color: var(--brand-text);
}

button.taxbit-button {
  border-radius: var(--brand-radius);
  font-family: var(--brand-font);
}

.taxbit-input,
.taxbit-select {
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  color: var(--brand-text);
  font-family: var(--brand-font);
  height: auto;
  padding: 8px 10px;
}

.taxbit-page-title { color: var(--brand-text); font-size: 1.4em; }
.taxbit-label { font-weight: 500; }

/* Status text */
.taxbit-error-message,
.taxbit-badge.invalid { color: #b91c1c; }
.taxbit-success-message,
.taxbit-badge.valid { color: #15803d; }
.taxbit-warning-message,
.taxbit-badge.pending { color: #b45309; }
.taxbit-info-message { color: #1d4ed8; }

Replace the status colors first. The defaults are the plain CSS keywords firebrick, green, goldenrod, and blue, which rarely sit well next to a brand palette.

Target individual elements

Every class below is a stable override target. Some carry no default styling at all — they're structural wrappers exposed so you have something to hook onto, and they're just as valid to target.

Page, header, and footer

ClassElement
.taxbit-pageThe whole form — controls width and padding
.taxbit-page-headerHeader bar
.taxbit-page-titleStep heading
.taxbit-page-sub-titleSubtitle under the heading
.taxbit-progress-statusThe "Step 2 of 5" text
.taxbit-select-languageLanguage picker in the header
.taxbit-page-main / .taxbit-page-contentBody of the form
.taxbit-page-footer / .taxbit-footerFooter region
.taxbit-page-actions / .taxbit-step-actionsAction bar holding the buttons
.taxbit-primary-actionsRight side — Next and Submit
.taxbit-secondary-actionsLeft side — Back and Cancel

Groups of questions

ClassElement
.taxbit-sectionA titled group of related questions
.taxbit-section-headerGroup header
.taxbit-section-header-titleGroup title
.taxbit-section-header-sub-titleGroup subtitle
.taxbit-section-header-actionAction slot at the right of the group header
.taxbit-section-contentQuestions inside the group
.taxbit-form-textStandalone paragraph of explanation

A single question

ClassElement
.taxbit-rowOne question — label plus input. Gets .taxbit-error when invalid
.taxbit-labelQuestion text
.taxbit-sub-labelHelper text under the question
.taxbit-row-content / .taxbit-row-value / .taxbit-input-groupWrappers around the input
.taxbit-row-actionsAction column at the right of a question
.taxbit-row-action-buttonSmall button in that column
.taxbit-row-edit-buttonEdit button
.taxbit-show-button / .taxbit-hide-buttonShow and hide toggles on masked fields such as TIN
.taxbit-input-status / .taxbit-input-status-footerValidation status shown under an input

Inputs

ClassElement
.taxbit-inputText input
.taxbit-textareaMulti-line input
.taxbit-input-fileFile upload
.taxbit-passwordMasked field
.taxbit-selectDropdown
.taxbit-country-code-selectCountry dropdown, width-constrained
.taxbit-select-day / -month / -yearThe three parts of a date input
.taxbit-checkbox / .taxbit-checkbox-labelCheckbox and its label; .disabled for the greyed-out state
.taxbit-radio-buttonsRadio group
.taxbit-radio-buttonOne option
.taxbit-radio-button-optionThat option's label
.taxbit-radio-button-sub-optionHelper text under an option
.taxbit-placeholderPlaceholder text
.taxbit-file-selected / .taxbit-filenameSelected-file display

Address fields

ClassElement
.taxbit-addressAddress block
.taxbit-address-line-1 / -line-2 / -region / -countryIndividual lines
.taxbit-city / .taxbit-state / .taxbit-postal-codeCity, state, and postal code

Buttons and status messages

ClassElement
button.taxbit-buttonAny button
.taxbit-button-disabledDisabled button
.taxbit-badgeValidation badge; .valid, .invalid, and .pending modifiers
.taxbit-error-messageError text
.taxbit-success-messageSuccess text
.taxbit-warning-messageWarning text
.taxbit-info-messageInformational text
.taxbit-spinner-iconLoading spinner
.taxbit-errorApplied to a question when its answer is invalid
.taxbit-disabledGreyed-out state

Target one form or one question

Three class families are generated at runtime from the form type or the question key, lowercased with dashes between words. Derive the name from the key rather than copying a fixed list — the list grows.

PatternExampleUse it to
.taxbit-form-<form-name>.taxbit-form-w-8ben-eStyle one form type differently
.taxbit-question-<field-name>.taxbit-question-tinStyle a single question
.taxbit-error-message-<field-name>.taxbit-error-message-tinStyle one question's error message
/* Monospace the TIN field so digits line up */
.taxbit-question-tin .taxbit-input {
  font-family: ui-monospace, monospace;
  letter-spacing: 0.05em;
}

/* Widen only W-8BEN-E, which has the most questions */
.taxbit-form-w-8ben-e .taxbit-page { max-width: 960px; }

Some taxbit-error-* names are element ids, not classes. Values like taxbit-error-dob are referenced by aria-describedby for screen readers and won't respond to CSS overrides. Use the .taxbit-error-message-<field-name> class for per-question error styling.

Replace the styling entirely

Import no base stylesheet. You write every rule, there's no specificity to work around, and nothing the SDK ships can shift under you on upgrade. The class reference above is the complete surface area.

import { TaxbitQuestionnaire } from '@taxbit/react-sdk';
import './taxbit-theme.css'; // entirely yours

This is usually right when you have an established design system, use Tailwind or a component library, or run strict design review. More work up front, less over time.

Resolve overrides that don't apply

When two rules target the same element, the more specific one wins. A few SDK rules are more specific than you'd expect: buttons are styled as button.taxbit-button rather than .taxbit-button, and the Next and Submit buttons through .taxbit-step-actions .taxbit-primary-actions > button.

/* Loses to the base stylesheet */
.taxbit-button { background: #6b21a8; }

/* Wins — qualified with the element, as the SDK rule is */
button.taxbit-button { background: #6b21a8; }

/* Wins — matches the SDK's longer path */
.taxbit-step-actions .taxbit-primary-actions > button { background: #6b21a8; }

Match the shape of the SDK rule rather than reaching for !important. If you import no base stylesheet, none of this applies — your rules are the only rules.

Default values

Relevant when you're extending the shipped look rather than replacing it.

ElementDefault
Primary buttonrgb(0, 96, 223); hover rgb(2, 80, 187); disabled rgb(170, 179, 187); text #ffffff
Secondary button#f9f9f9; hover #e9e9e9; text #1a1a1a
Body text and headings#12263f
Borders and dividers#e4ebf6; input borders #bfcde2
Status colorssuccess green, error firebrick, warning and pending goldenrod, info blue
Form widthmax-width: 600px
Input and select height33px
Border radius4px inputs, 8px buttons
Font stackInter, system-ui, Avenir, Helvetica, Arial, sans-serif

Best practices

  • Start from minimal.css when you intend to restyle. It gives you structure and status colors without a full visual opinion to unwind, so you spend your time writing rules rather than cancelling them.
  • Declare your brand values once at the top of your override file. Your own CSS variables on .taxbit-page keep colors, fonts, and radius in one place and cascade to every rule below.
  • Keep all overrides in one stylesheet, imported after the SDK's. One file makes the full extent of your customization reviewable and keeps import order easy to reason about.
  • Target class names directly. Flat, class-based selectors survive internal DOM changes; selectors that walk the form's structure don't.
  • Replace the default status colors. firebrick, green, goldenrod, and blue are deliberately generic and are the fastest visual tell that a form isn't yours.
  • Style TaxbitCuringDocumentation and TaxbitQuestionnaire together. They render the same classes, so one stylesheet covers both — verify the curing flow after restyling rather than treating it separately.
  • Re-check your overrides when you upgrade. DOM and class changes are recorded in the SDK changelog. If you've styled deeply, read it before bumping the version.

Pitfalls

  • Importing your stylesheet before the SDK's. Later rules win. If your CSS appears to do nothing at all, check import order before anything else.
  • Importing style/index.css in production. It styles :root and html, so fonts, text color, and padding change across your entire page rather than inside the form.
  • Writing bare .taxbit-button rules. The SDK qualifies its button selectors with the element name, so an unqualified class selector silently loses.
  • Styling taxbit-error-* ids. Several of those names are element ids used for aria-describedby, not classes. Per-question error styling uses .taxbit-error-message-<field-name>.
  • Depending on the form's internal structure. Long descendant chains, :nth-child, and sibling selectors break when the form's internals change. Class names are the contract; nesting depth and tag names are not.
  • Setting input height without clearing the default. .taxbit-input and .taxbit-select ship at height: 33px. Set height: auto and use padding instead of fighting the fixed value.
  • Hard-coding the list of generated class names. .taxbit-question-* and .taxbit-form-* names are derived from keys and grow with new fields and form types. Build them from the key.

Next steps