UML Component Diagrams

deployable units and interface contracts, illustrated with TextFinder

1.  What a Component Diagram Shows

A component diagram shows independently deployable units and the interface contracts they expose or depend on. Each component is a black box: its internal structure is hidden, and it interacts with the world only through named interfaces. One interface is provided - the component implements it and offers it to any caller. Another is required - the component depends on some other unit to supply it. The pairing of a provided interface on one component with a required interface on another is an assembly connector. It says: these two components can be wired together because one's output matches the other's input. The diagram does not say which concrete type satisfies the requirement - that is a deployment or configuration decision, not a design constraint. Component diagrams sit between package diagrams and deployment diagrams in the UML structural hierarchy. Package diagrams show compilation units; component diagrams show runtime-substitutable units with explicit interface contracts; deployment diagrams show which hardware nodes host which components. A system can be described usefully at any of those levels without touching the others.

2.  Notation

The core vocabulary is small: components, two kinds of interface symbol, and the assembly connector that joins them.
ElementMeaning
Component A rectangle labeled <<component>> or carrying the component icon (a small rectangle with two tabs on its left edge). The body may list internal parts or be left empty when only the interface matters.
Provided interface (lollipop) A filled circle on a short line extending from the component boundary. The component implements this interface and makes it available to any requirer. Named on or beside the circle.
Required interface (socket) A half-circle (open arc) on a short line extending from the component boundary. The component depends on some other component to supply this interface at runtime.
Assembly connector A line connecting a provided lollipop to a required socket. The lollipop fits inside the socket, forming a visual "ball-and-socket" joint. It asserts that the provider's interface satisfies the requirer's contract.
Port A small square on the component boundary through which a specific interface is exposed or consumed. Ports name the interaction point independently of the interface type, allowing one component to expose the same interface through different ports for different clients.
Dependency arrow A dashed arrow when a full assembly connector is not warranted - for example, when the interface contract is informal or when the diagram is at a sketch level.
Mermaid has no native component diagram renderer. The diagrams on this page use flowchart with labeled edges to approximate the assembly connector, and <<component>> stereotypes in node labels to mark each component. Arrow direction follows the convention: provider → requirer.

3.  Notation in Practice

The diagram below shows two components wired by an assembly connector and one component with a required interface that has no provider in scope - a deliberately unresolved dependency, signaling that a third component must be supplied at deployment time.
flowchart LR
    CompA["<<component>>\nComponentA"]
    CompB["<<component>>\nComponentB"]
    CompC["<<component>>\nComponentC"]

    CompA -->|"«provides» IServiceA"| CompB
    CompC -.->|"«requires» ILogger\n(unresolved)"| ext["<<external>>\nLogger"]
      

Figure 1. Assembly connector notation.

A solid labeled edge links ComponentA's provided IServiceA to ComponentB's required interface. ComponentC has an unresolved required interface shown as a dashed dependency to an external placeholder.

4.  TextFinder Interface Contracts

TextFinder has four components. Three are library components with a single provided interface each. EntryPoint is the wiring component: it requires all three library interfaces and additionally provides the callback interface that DirNav requires. The callback provision is the structurally interesting point - it reverses the usual direction and makes DirNav a client of EntryPoint at runtime.
Component Provided interface Required interface
CommandLine ICmdLine - parse(args), get(key) → Option, get_all(key) → Vec none
DirNav IDirNav - add_pattern(ext), search(path, callback) IDirEvent - do_dir(dir), do_file(file)
Output IOutput - set_regex(pattern), find(path) → bool none
EntryPoint IDirEvent (via TfAppl) - do_dir(dir), do_file(file) ICmdLine, IDirNav, IOutput

5.  TextFinder Component Diagram

Four assembly connectors wire the system. Three flow from library components toward EntryPoint - the libraries provide, EntryPoint consumes. The fourth runs in the opposite direction: EntryPoint provides IDirEvent, which DirNav requires. That reversed edge is the callback pattern made structurally explicit.
flowchart TD
    CL["<<component>>\nCommandLine"]
    DN["<<component>>\nDirNav"]
    EP["<<component>>\nEntryPoint\n(hosts TfAppl)"]
    OUT["<<component>>\nOutput"]

    CL  -->|"«ICmdLine»"| EP
    OUT -->|"«IOutput»"| EP
    DN  -->|"«IDirNav»"| EP
    EP  -->|"«IDirEvent»"| DN
      

Figure 2. TextFinder component diagram.

Three arrows converge on EntryPoint from the library components. One arrow leaves EntryPoint toward DirNav - the callback interface IDirEvent that DirNav requires and EntryPoint provides via TfAppl.

6.  Reading the Diagram

Two structural facts stand out that are not visible in the package diagram of the same system. DirNav has two edges, pointing in opposite directions. The IDirNav edge points toward EntryPoint: DirNav provides, EntryPoint consumes. The IDirEvent edge points away from EntryPoint: EntryPoint provides, DirNav consumes. DirNav is simultaneously a service provider and a service consumer in this assembly. The package diagram shows only the IDirNav direction - the import - and hides the callback requirement entirely. CommandLine and Output are pure providers. No edge leaves them. They have no required interfaces - they depend on nothing outside themselves. This makes them the easiest components to test in isolation and the first candidates for reuse in a different assembly. The component diagram makes that substitutability visible without reading any source. EntryPoint is the only component that appears on both ends of multiple edges. It is the assembly hub - the component whose job is precisely to connect the others. Identifying the assembly hub in a component diagram is useful: it is the component most likely to need updating when an interface changes, and the component that has the broadest test surface.

7.  Component vs. Package Diagrams

Both diagram types are structural, and for a simple tool like TextFinder the two views look similar. The distinction becomes important in larger systems.
Concern Package diagram Component diagram
Primary question Which compilation unit imports which? Which runtime unit provides or requires which interface?
Dependency edge means A imports B - direct type dependency. A provides an interface that B requires - contract dependency.
Substitutability Not expressed. A depends on B, not on a B substitute. Explicit. Any component satisfying the interface can fill the slot.
Callback / inversion Hidden. Import arrows all point one way. Visible. A reversed assembly edge shows who provides the callback.
Granularity One package = one namespace or module. One component = one deployable unit, which may span multiple packages.
TextFinder fit Shows that EntryPoint imports all three library packages. Shows that DirNav both provides IDirNav and requires IDirEvent from EntryPoint.
In a plugin system, a microservice mesh, or any architecture where components are loaded or replaced at runtime, the component diagram is the more useful document. In a statically compiled monolith where substitution never happens in practice, the package diagram is often sufficient.

8.  When to Draw One

Draw a component diagram when the question involves interface contracts and substitutability rather than import structure or type detail. Specific triggers: When the interesting question is about compilation boundaries and import rules, use a package diagram. When it is about type hierarchies and member relationships, use a class diagram. Component diagrams earn their place when interface contracts and runtime substitution are the design concern.

9.  References

ResourceDescription
Project Story: TextFinder Architecture, CLI, performance, and code metrics for all five implementations.
UML Package Diagrams The compilation-boundary view of the same TextFinder structure - the closest structural diagram to compare against.
UML Class Diagrams The type-level view showing the members and relationships inside each component.
Mermaid flowchart syntax Full syntax reference for the Mermaid notation used to approximate component diagrams on this page.
UML Component Diagrams Overview Formal UML notation reference covering components, ports, interfaces, connectors, and substitution rules.