Semantic specifications of programming languages typically have poor modularity. This hinders reuse of parts of the semantics of one language when specifying a different language -- even when the two languages have many constructs in common -- and evolution of a language may require major reformulation of its semantics. Such drawbacks have discouraged language developers from using formal semantics to document their designs. In the PlanCompS project, we have developed a component-based approach to semantics. Here, we explain its modularity aspects, and present an illustrative case study. Our approach provides good modularity, facilitates reuse, and supports co-evolution of languages and their formal semantics. It could be particularly useful in connection with domain-specific languages and language-driven software development.