Skip to content
EspañolEnglish
All components (204)

Invoice lines

Management · InvoiceLinesEditor · .amset-invoice

What it is and when to use it

The lines of an invoice, editable: description, quantity, unit price, discount, VAT and income-tax withholding (IRPF) per line, with the amount of each one and the breakdown below: taxable base, VAT by rate, withholding by rate and total.

How it calculates (calculateInvoice, which is also exported on its own)

  • Each line: quantity × price, minus the discount, rounded to the cent.
  • VAT and withholding are calculated once per rate, on the sum of the bases of that rate: that way they match the breakdown printed on the invoice (calculating them line by line throws cents off).
  • The equivalence surcharge (a customer under that regime, typical of retail) is added to the VAT according to its rate: 5.2% with 21%, 1.4% with 10% and 0.5% with 4% (article 161 of Law 37/1992). It has its own row in the breakdown, also once per rate.
  • Total = base + VAT + surcharge − withholding. A negative quantity is a credit note.

When to use it

  • Issuing invoices, quotes or credit notes. onChange hands over the lines and the totals already calculated.
  • equivalenceSurcharge puts the equivalence surcharge on the WHOLE invoice; with surchargePerLine each line gets its "Equivalence surcharge" checkbox and the line's overrides the invoice's. surchargeRates changes the rates (for example the transitional 0.62% with 5%, which is not the default).
  • withWithholding={false} removes the withholding column; vatRates and withholdingRates change the rates offered (the Canary Islands' IGIC, another country); minLines and maxLines bound how many lines there are.

When not to

  • Just showing an invoice that has already been issued: a Table or OrderSummary.
  • Several currencies on the same invoice or pro-rata: it does not cover them. Nor does it decide whether your customer is under the equivalence surcharge: you know that, and you tell it with equivalenceSurcharge.

Keyboard: lines are walked with Tab. "Add line" leaves focus on the description of the new one; when one is removed, focus moves to the previous one.

Accessibility: each line is a group ("Line 2"); adding and removing are announced; the total is in role="status". On a wide screen the labels are shown only on the first line and remain present for the screen reader on the others.

What it looks like

Invoice lines
21% · standard
10% · reduced
4% · super-reduced
0% · exempt
None
7%
15%
19%
Amount€1,800.00
21% · standard
10% · reduced
4% · super-reduced
0% · exempt
None
7%
15%
19%
Amount€324.00
21% · standard
10% · reduced
4% · super-reduced
0% · exempt
None
7%
15%
19%
Amount€74.70
Taxable base
€2,198.70
VAT 21% on €2,124.00
€446.04
VAT 4% on €74.70
€2.99
Withholding 15% on €2,124.00
-€318.60
Invoice total
Invoice total: €2,329.13

<InvoiceLinesEditor
  label="Invoice lines"
  initialValue={lineas}
  onChange={setLineas}
/>

Props

Import it with import { InvoiceLinesEditor } from '@amset/ui'. Required props are marked.

PropTypeWhat it does
labelrequiredstringRequired: names the group of lines for the screen reader.
classNamestringMerged with the library classes; it does not replace them.
currencystringThe currency. `EUR` by default.
defaultVatRatenumberThe VAT of a new line. By default, 21.
disabledboolean—
equivalenceSurchargebooleanEquivalence surcharge on the WHOLE invoice (a customer under that regime: retail). It is added to the VAT of each line according to its rate (5.2% with 21%, 1.4% with 10%, 0.5% with 4%) and appears in the breakdown. Defaults to `false`.
errorstringError from outside (from the server).
hintstring—
initialValuereadonly InvoiceLine[]The lines to start with, without controlling them from outside. Without them, one empty line.
maxLinesnumberThe maximum number of lines. No limit by default.
minLinesnumberThe minimum number of lines: you cannot remove below it. By default, 1.
onChange(lines: readonly InvoiceLine[], totals: InvoiceTotals) => voidNotifies with the lines and the totals already calculated each time something changes.
readOnlyboolean—
surchargePerLinebooleanAn "Equivalence surcharge" checkbox on each line, to decide it line by line: the checkbox of a line overrides `equivalenceSurcharge`. Defaults to `false`.
surchargeRatesReadonly<Record<number, number>>The surcharge for each VAT rate, as a percentage. Defaults to the Spanish rates in force (`SPANISH_SURCHARGE_RATES`).
valuereadonly InvoiceLine[]The lines, controlled from outside.
vatRatesreadonly number[]The VAT rates offered. By default, the Spanish ones (21, 10, 4 and 0).
withholdingRatesreadonly number[]The income-tax withholding rates (IRPF) offered. By default, 0, 7, 15 and 19.
withWithholdingbooleanWith `false` there is no withholding column. By default, `true`.

It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.

CSS variables

These CSS variables are how you adapt it. Declare them on the component's selector, not on :root: the stylesheet redeclares them in the rule itself, and a declaration on the same element always wins.

VariableDefault
--amset-invoice-gapvar(--amset-space-3)

How to change it

.amset-invoice {
  --amset-invoice-gap: ...;
}

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: